если бы у меня было 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 отдельными индексами.
Только вы можете выполнить соответствующие тесты и достичь правильного баланса между всеми этими проблемами.