Рассмотрение производительности: разброс строк в нескольких таблицах против концентрации всех строк в одной таблице
Рассмотрение производительности: разброс строк в нескольких таблицах против концентрации всех строк в одной таблице.
Привет.
Мне нужно регистрировать информацию о каждом шаге, который происходит в приложении в БД SQL. Есть определенные таблицы, я хочу, чтобы журнал был связан с: Продукт - должен регистрироваться, когда продукт был создан изменен и т. д. Порядок-такой же, как и выше Доставка - то же самое и т.д. и т.д. и т.д.
Данные нужно будет часто извлекать.
У меня есть несколько идей о том, как чтобы сделать это:
- Есть таблица журнала, которая будет содержать столбцы для всех этих таблиц, то когда я хочу представить данные в пользовательском интерфейсе для определенного продукта будет делать select * from Log where LogId = Product.Продуктид. Я знаю, что это может быть забавно иметь много cols, но у меня такое чувство, что производительность будет лучше. С другой стороны, в этой таблице будет огромное количество строк.
- Есть много таблиц журналов для каждого типа журналов (ProductLogs, OrderLogs и т. д.) Мне действительно не нравится эта идея, поскольку она не согласована и имеет много таблиц с одинаковой структурой, не имеет смысла, но (?) это может быть быстрее при поиске в таблице, которая имеет меньшее количество строк (я ошибаюсь?).
- согласно инструкции № 1, я мог бы сделать вторую таблицу "многие к одному", которая будет иметь logid, TableNameId и rowid cols, и будет ссылаться на строку журнала для многих строк таблицы в БД, чем будет иметь UDF для извлечения данных (например, log id 234 принадлежит таблице Customer at CustomerId 345 и к ней же относится к таблице Product table where productId = RowId); я думаю, что это самый хороший способ сделать это, но опять же, там может быть огромное количество строк, это замедлит поиск? или вот как это должно быть сделано, что скажешь?...
Пример № 3 в приведенном выше списке:
CREATE TABLE [dbo].[Log](
[LogId] [int] IDENTITY(1,1) NOT NULL,
[UserId] [int] NULL,
[Description] [varchar](1024) NOT NULL,
CONSTRAINT [PK_Log] PRIMARY KEY CLUSTERED
(
[LogId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Log] WITH CHECK ADD CONSTRAINT [FK_Log_Table] FOREIGN KEY([UserId])
REFERENCES [dbo].[Table] ([TableId])
GO
ALTER TABLE [dbo].[Log] CHECK CONSTRAINT [FK_Log_Table]
---------------------------------------------------------------------
CREATE TABLE [dbo].[LogReference](
[LogId] [int] NOT NULL,
[TableName] [varchar](32) NOT NULL,
[RowId] [int] NOT NULL,
CONSTRAINT [PK_LogReference] PRIMARY KEY CLUSTERED
(
[LogId] ASC,
[TableName] ASC,
[RowId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[LogReference] WITH CHECK ADD CONSTRAINT [FK_LogReference_Log] FOREIGN KEY([LogId])
REFERENCES [dbo].[Log] ([LogId])
GO
ALTER TABLE [dbo].[LogReference] CHECK CONSTRAINT [FK_LogReference_Log]
---------------------------------------------------------------------
CREATE FUNCTION GetLog
(
@TableName varchar(32),
@RowId int
)
RETURNS
@Log TABLE
(
LogId int not null,
UserId int not null,
Description varchar(1024) not null
)
AS
BEGIN
INSERT INTO @Log
SELECT [Log].LogId, [Log].UserId, [Log].Description
FROM [Log] INNER JOIN
LogReference ON [Log].LogId = LogReference.LogId
WHERE (LogReference.TableName = @TableName) AND (LogReference.RowId = @RowId)
RETURN
END
GO
4 ответа:
Я определенно выбрал бы вариант 3 по нескольким причинам:
Данные должны быть в полях таблицы, а не в виде имени таблицы (вариант 2) или имени Поля (Вариант 1). Таким образом, с базой данных становится легче работать и легче поддерживать ее.
Более узкие таблицы обычно работают лучше. Количество строк влияет на производительность меньше, чем количество полей.
Если у вас есть поле для каждой таблицы (Вариант 1), вы, вероятно, получите много пустых полей, когда всего несколько на таблицы влияет операция.
Будьте осторожны с предварительной оптимизацией баз данных. Большинство баз данных достаточно быстры и несколько сложны. Вы хотите сначала провести тест на эффективность.
Во-вторых, если все поместить в одну таблицу, то результаты, которые вы хотите получить, будут находиться в кэше, что значительно ускорит производительность. К сожалению, это также делает гораздо более вероятным, что вам придется искать гигантскую таблицу, чтобы найти то, что вы ищете. Это можно частично решить с помощью индекса, но индексы этого не делают. приходите бесплатно (они делают написание более дорогим, например).
Мой совет - сделать тест, чтобы увидеть, действительно ли производительность имеет значение, а затем протестировать различные сценарии, чтобы увидеть, какой из них самый быстрый.
Если вы говорите о больших объемах данных (миллионы строк+), то вы получите преимущество от использования различных таблиц для их хранения.
Например, базовый пример 50 миллионов записей журнала, предполагая 5 различных "типов" таблицы журнала Лучше иметь 5 х 10 миллионов таблиц строк, чем 1 х 50 миллионов таблиц строк
Производительность вставки будет лучше с отдельными таблицами-индексы на каждой таблице будут меньше и поэтому быстрее / легче обновляться/поддерживаться в составе операция вставки
Производительность чтения будет лучше с отдельными таблицами-меньше данных для запроса, меньше индексов для обхода. Кроме того, похоже, что вам потребуется сохранить дополнительный столбец, чтобы определить, какой тип записи журнала является записью (продукт, доставка....)
- обслуживание меньших таблиц менее болезненно (статистика, дефрагментация/перестройка индексов и т. д.)
По сути, речь идет о секционировании данных. Начиная с SQL 2005 и далее, он имеет встроенную поддержку для секционирование (см. здесь ), но для этого вам понадобится Enterprise Edition, который в основном позволяет разбивать данные в одной таблице для повышения производительности (например, у вас будет одна таблица журнала, а затем определить, как данные в ней секционируются)
Я недавно слушал интервью с одним из архитекторов eBay, который подчеркнул важность разделения, когда требуется производительность и масштабируемость, и я полностью согласен с этим, основываясь на своем опыте.
Попробуйте реализовать свой уровень доступа к данным таким образом, чтобы при необходимости можно было переходить от одной модели базы данных к другой - таким образом, вы просто выбираете одну и беспокоитесь о последствиях для производительности позже.
Без проведения некоторого тестирования производительности и точного представления о видах нагрузки, которую вы собираетесь получить, будет трудно оптимизировать, поскольку производительность зависит от ряда факторов, таких как количество операций чтения, количество операций записи и независимо от того, выполняется ли чтение и запись. скорее всего, они конфликтуют и вызывают блокировку.
Я бы предпочел вариант 1 Кстати - его проще всего сделать, и есть ряд настроек, которые вы можете сделать, чтобы помочь исправить различные виды проблем, которые у вас могут возникнуть.