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

StackOverflow https://stackoverflow.com/questions/1142296

Вопрос

Учет производительности:Распределяйте строки по нескольким таблицам, а не концентрируйте все строки в одной таблице.

Привет.

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

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

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

  1. Имейте таблицу журнала, которая будет содержать столбцы для всех этих таблиц, затем, когда я хочу представить данные в пользовательском интерфейсе для определенного продукта, я выберу * из журнала, где LogId = Product.ProductId.Я знаю, что это может быть забавно иметь много столбцов, но у меня такое ощущение, что производительность будет лучше.С другой стороны, в этой таблице будет огромное количество строк.
  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
Это было полезно?

Решение

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

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

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

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

Другие советы

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

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

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

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

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

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top