Рассмотрение производительности: разброс строк в нескольких таблицах против концентрации всех строк в одной таблице


Рассмотрение производительности: разброс строк в нескольких таблицах против концентрации всех строк в одной таблице.

Привет.

Мне нужно регистрировать информацию о каждом шаге, который происходит в приложении в БД SQL. Есть определенные таблицы, я хочу, чтобы журнал был связан с: Продукт - должен регистрироваться, когда продукт был создан изменен и т. д. Порядок-такой же, как и выше Доставка - то же самое и т.д. и т.д. и т.д.

Данные нужно будет часто извлекать.

У меня есть несколько идей о том, как чтобы сделать это:

  1. Есть таблица журнала, которая будет содержать столбцы для всех этих таблиц, то когда я хочу представить данные в пользовательском интерфейсе для определенного продукта будет делать select * from Log where LogId = Product.Продуктид. Я знаю, что это может быть забавно иметь много cols, но у меня такое чувство, что производительность будет лучше. С другой стороны, в этой таблице будет огромное количество строк.
  2. Есть много таблиц журналов для каждого типа журналов (ProductLogs, OrderLogs и т. д.) Мне действительно не нравится эта идея, поскольку она не согласована и имеет много таблиц с одинаковой структурой, не имеет смысла, но (?) это может быть быстрее при поиске в таблице, которая имеет меньшее количество строк (я ошибаюсь?).
  3. согласно инструкции № 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 4

4 ответа:

Я определенно выбрал бы вариант 3 по нескольким причинам:

Данные должны быть в полях таблицы, а не в виде имени таблицы (вариант 2) или имени Поля (Вариант 1). Таким образом, с базой данных становится легче работать и легче поддерживать ее.

Более узкие таблицы обычно работают лучше. Количество строк влияет на производительность меньше, чем количество полей.

Если у вас есть поле для каждой таблицы (Вариант 1), вы, вероятно, получите много пустых полей, когда всего несколько на таблицы влияет операция.

Будьте осторожны с предварительной оптимизацией баз данных. Большинство баз данных достаточно быстры и несколько сложны. Вы хотите сначала провести тест на эффективность.

Во-вторых, если все поместить в одну таблицу, то результаты, которые вы хотите получить, будут находиться в кэше, что значительно ускорит производительность. К сожалению, это также делает гораздо более вероятным, что вам придется искать гигантскую таблицу, чтобы найти то, что вы ищете. Это можно частично решить с помощью индекса, но индексы этого не делают. приходите бесплатно (они делают написание более дорогим, например).

Мой совет - сделать тест, чтобы увидеть, действительно ли производительность имеет значение, а затем протестировать различные сценарии, чтобы увидеть, какой из них самый быстрый.

Если вы говорите о больших объемах данных (миллионы строк+), то вы получите преимущество от использования различных таблиц для их хранения.

Например, базовый пример 50 миллионов записей журнала, предполагая 5 различных "типов" таблицы журнала Лучше иметь 5 х 10 миллионов таблиц строк, чем 1 х 50 миллионов таблиц строк

  • Производительность вставки будет лучше с отдельными таблицами-индексы на каждой таблице будут меньше и поэтому быстрее / легче обновляться/поддерживаться в составе операция вставки

  • Производительность чтения будет лучше с отдельными таблицами-меньше данных для запроса, меньше индексов для обхода. Кроме того, похоже, что вам потребуется сохранить дополнительный столбец, чтобы определить, какой тип записи журнала является записью (продукт, доставка....)

  • обслуживание меньших таблиц менее болезненно (статистика, дефрагментация/перестройка индексов и т. д.)

По сути, речь идет о секционировании данных. Начиная с SQL 2005 и далее, он имеет встроенную поддержку для секционирование (см. здесь ), но для этого вам понадобится Enterprise Edition, который в основном позволяет разбивать данные в одной таблице для повышения производительности (например, у вас будет одна таблица журнала, а затем определить, как данные в ней секционируются)

Я недавно слушал интервью с одним из архитекторов eBay, который подчеркнул важность разделения, когда требуется производительность и масштабируемость, и я полностью согласен с этим, основываясь на своем опыте.

Попробуйте реализовать свой уровень доступа к данным таким образом, чтобы при необходимости можно было переходить от одной модели базы данных к другой - таким образом, вы просто выбираете одну и беспокоитесь о последствиях для производительности позже.

Без проведения некоторого тестирования производительности и точного представления о видах нагрузки, которую вы собираетесь получить, будет трудно оптимизировать, поскольку производительность зависит от ряда факторов, таких как количество операций чтения, количество операций записи и независимо от того, выполняется ли чтение и запись. скорее всего, они конфликтуют и вызывают блокировку.

Я бы предпочел вариант 1 Кстати - его проще всего сделать, и есть ряд настроек, которые вы можете сделать, чтобы помочь исправить различные виды проблем, которые у вас могут возникнуть.