Повышение производительности одного столбца по сравнению с индексами нескольких столбцов - PullRequest
7 голосов
/ 05 декабря 2011

Привет, мне было интересно, каковы накладные расходы производительности для одного столбца по сравнению с индексами нескольких столбцов с точки зрения вставок. Так, например, если бы у меня было 3 индекса по одному столбцу, это было бы лучше для вставок в эту таблицу, а не по 1 индексу с несколькими столбцами. Когда я говорю о производительности, меня интересует грубая скорость.

Ответы [ 4 ]

5 голосов
/ 05 декабря 2011

Затраты INSERT на INDEX обычно незначительны независимо от одного или нескольких столбцов.

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

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

Общее правило - учитывать производительность запроса, а не производительность вставки, если только вы не можете предсказать или увидеть конкретную проблему свставки.

2 голосов
/ 05 декабря 2011

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

1 голос
/ 05 декабря 2011

если бы у меня было 3 одностолбцовых индекса, это было бы лучше для вставок в эту таблицу, а не 1 индекс с несколькими столбцами.

Для операций, которые изменяют данные, один индекс с 3 столбцами должен быть быстрее, чем 3 индекса с одним столбцом, по следующим причинам:

  • Обновление индекса требует поиска в B-дереве правильного места для выполнения модификации. Выполнение поиска по одному индексу (даже если оно составное), как правило, выполняется быстрее, чем выполнение 3 поисков по 3 индексам.
  • Каждое B-дерево лист содержит строку «указатель». 1 индекс будет иметь в 3 раза меньше указателей строк, чем 3 индекса (без учета значения NULL, которое обычно не индексируется). И меньше часто быстрее из-за эффектов кэширования.
  • 1 index может имеет тенденцию иметь меньшее разбиение и объединение узлов B-Tree по сравнению с 3 индексами.

Рассмотрим следующий тест MS SQL Server:

CREATE TABLE ONE_INDEX (
    ID int PRIMARY KEY NONCLUSTERED,
    F1 uniqueidentifier NOT NULL,
    F2 uniqueidentifier NOT NULL,
    F3 uniqueidentifier NOT NULL
);
CREATE INDEX ONE_INDEX_IE1 ON ONE_INDEX (F1, F2, F3);

CREATE TABLE THREE_INDEXES (
    ID int PRIMARY KEY NONCLUSTERED,
    F1 uniqueidentifier NOT NULL,
    F2 uniqueidentifier NOT NULL,
    F3 uniqueidentifier NOT NULL
);
CREATE INDEX THREE_INDEXES_IE1 ON THREE_INDEXES (F1);
CREATE INDEX THREE_INDEXES_IE2 ON THREE_INDEXES (F2);
CREATE INDEX THREE_INDEXES_IE3 ON THREE_INDEXES (F3);
GO



SET NOCOUNT ON
DECLARE @t DATETIME;
DECLARE @id INT;
DECLARE @count INT;
SET @count = 100000;



PRINT 'ONE_INDEX:'

SET @t = CURRENT_TIMESTAMP
SET @id = 0;
BEGIN TRANSACTION;
WHILE @id < @count BEGIN
    INSERT INTO ONE_INDEX VALUES(@id, NEWID(), NEWID(), NEWID());
    SET @id = @id + 1;
END
COMMIT TRANSACTION;
PRINT '    INSERT ' + CAST(@count AS VARCHAR) + ' rows: ' + CAST(DATEDIFF(ms, @t, CURRENT_TIMESTAMP) AS VARCHAR) + ' ms';

SET @t = CURRENT_TIMESTAMP
SET @id = 0;
BEGIN TRANSACTION;
WHILE @id < @count BEGIN
    UPDATE ONE_INDEX SET F1 = NEWID(), F2 = NEWID(), F3 = NEWID() WHERE ID = @id
    SET @id = @id + 1;
END
COMMIT TRANSACTION;
PRINT '    UPDATE ' + CAST(@count AS VARCHAR) + ' rows: ' + CAST(DATEDIFF(ms, @t, CURRENT_TIMESTAMP) AS VARCHAR) + ' ms';

SET @t = CURRENT_TIMESTAMP
DELETE FROM ONE_INDEX;
PRINT '    DELETE ' + CAST(@count AS VARCHAR) + ' rows: ' + CAST(DATEDIFF(ms, @t, CURRENT_TIMESTAMP) AS VARCHAR) + ' ms';



PRINT 'THREE_INDEXES:'

SET @t = CURRENT_TIMESTAMP
SET @id = 0;
BEGIN TRANSACTION;
WHILE @id < @count BEGIN
    INSERT INTO THREE_INDEXES VALUES(@id, NEWID(), NEWID(), NEWID());
    SET @id = @id + 1;
END
COMMIT TRANSACTION;
PRINT '    INSERT ' + CAST(@count AS VARCHAR) + ' rows: ' + CAST(DATEDIFF(ms, @t, CURRENT_TIMESTAMP) AS VARCHAR) + ' ms';

SET @t = CURRENT_TIMESTAMP
SET @id = 0;
BEGIN TRANSACTION;
WHILE @id < @count BEGIN
    UPDATE THREE_INDEXES SET F1 = NEWID(), F2 = NEWID(), F3 = NEWID() WHERE ID = @id
    SET @id = @id + 1;
END
COMMIT TRANSACTION;
PRINT '    UPDATE ' + CAST(@count AS VARCHAR) + ' rows: ' + CAST(DATEDIFF(ms, @t, CURRENT_TIMESTAMP) AS VARCHAR) + ' ms';

SET @t = CURRENT_TIMESTAMP
DELETE FROM THREE_INDEXES;
PRINT '    DELETE ' + CAST(@count AS VARCHAR) + ' rows: ' + CAST(DATEDIFF(ms, @t, CURRENT_TIMESTAMP) AS VARCHAR) + ' ms';
GO



DROP TABLE ONE_INDEX;
DROP TABLE THREE_INDEXES;
GO

Который (на моем MS SQL Server Express 2008 R2 под виртуальной машиной) печатает:

ONE_INDEX:
    INSERT 100000 rows: 4173 ms
    UPDATE 100000 rows: 5530 ms
    DELETE 100000 rows: 2706 ms
THREE_INDEXES:
    INSERT 100000 rows: 6640 ms
    UPDATE 100000 rows: 10436 ms
    DELETE 100000 rows: 3516 ms

Увеличение @count до 1000000 приводит к:

ONE_INDEX:
    INSERT 1000000 rows: 40143 ms
    UPDATE 1000000 rows: 55796 ms
    DELETE 1000000 rows: 95576 ms
THREE_INDEXES:
    INSERT 1000000 rows: 61360 ms
    UPDATE 1000000 rows: 91766 ms
    DELETE 1000000 rows: 99500 ms

Обратите внимание, что в большинстве рабочих нагрузок чтение превышает количество записей, поэтому усилия по оптимизации обычно отдают приоритет покрытию SELECT индексами за счет INSERT, UPDATE и DELETE. Кроме того, составной индекс будет влиять на производительность запросов по-другому по сравнению с 3 отдельными индексами.

Только вы можете выполнить соответствующие тесты и достичь правильного баланса между всеми этими проблемами.

0 голосов
/ 05 декабря 2011

Имейте в виду, что составной индекс, состоящий из 3 столбцов, таких как LastName, FirstName и City, бесполезен при поиске по City. Так что в этом случае вам понадобится индекс только для города.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...