Оценка производительности: распределение строк в нескольких таблицах по сравнению с концентрацией всех строк в одной таблице - PullRequest
4 голосов
/ 17 июля 2009

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

Привет.

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

Данные нужно будет часто получать.

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

  1. Имейте таблицу журнала, которая будет содержать столбцы для всех этих таблиц, тогда, когда я хочу представить данные в пользовательском интерфейсе для определенного продукта, выберите * из журнала, где LogId = Product.ProductId. Я знаю, что было бы смешно иметь много cols, но я чувствую, что производительность будет лучше. С другой стороны, в этой таблице будет огромное количество строк.
  2. Наличие большого количества таблиц журналов для каждого типа журналов (ProductLogs, OrderLogs и т. Д.). Мне действительно не нравится эта идея, поскольку она не согласована и иметь много таблиц с одинаковой структурой не имеет смысла, но (?) Это может быстрее при поиске в таблице с меньшим количеством строк (не так ли?).
  3. Согласно заявлению № 1, я мог бы создать вторую таблицу многие-к-одному, которая будет иметь столбцы LogId, TableNameId и RowId и будет ссылаться на строку журнала во многих строках таблицы в БД, чем будет иметь UDF для получения данных (например, идентификатор журнала 234 принадлежит таблице Customer с CustomerId 345 и таблице Product, где 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 голосов
/ 17 июля 2009

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

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

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

2 голосов
/ 17 июля 2009

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

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

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

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

  • ОБСЛУЖИВАНИЕ в небольших таблицах менее болезненно (статистика, дефрагментация / перестроение индекса и т. Д.)

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

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

1 голос
/ 17 июля 2009

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

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

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

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

0 голосов
/ 17 июля 2009

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

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

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

...