В своем вопросе вы детализируете подготовленные вами тесты, в которых вы «доказываете», что опция добавления выполняется быстрее, чем сравнение отдельных столбцов. Я подозреваю, что ваша методология тестирования может быть ошибочной по нескольким причинам, на что ссылались @gbn и @srutzky.
Во-первых, вам нужно убедиться, что вы не тестируете SQL Server Management Studio (или любой другой клиент, который вы используете). Например, если вы запускаете SELECT *
из таблицы с 3 миллионами строк, вы в основном тестируете способность SSMS извлекать строки из SQL Server и отображать их на экране. Вам гораздо лучше использовать что-то подобное, SELECT COUNT(1)
что устраняет необходимость протягивать миллионы строк по сети и отображать их на экране.
Во-вторых, вам нужно знать о кеше данных SQL Server. Как правило, мы тестируем скорость чтения данных из хранилища и обработки этих данных из холодного кэша (т. Е. Буферы SQL Server пусты). Время от времени имеет смысл проводить все тестирование с использованием «теплого кэша», но вам необходимо явно подходить к тестированию с учетом этого.
Для теста с холодным кэшем необходимо запускать CHECKPOINT
и DBCC DROPCLEANBUFFERS
перед каждым запуском теста.
Для теста, который вы задали в своем вопросе, я создал следующий тестовый стенд:
IF COALESCE(OBJECT_ID('tempdb..#SomeTest'), 0) <> 0
BEGIN
DROP TABLE #SomeTest;
END
CREATE TABLE #SomeTest
(
TestID INT NOT NULL
PRIMARY KEY
IDENTITY(1,1)
, A INT NOT NULL
, B FLOAT NOT NULL
, C MONEY NOT NULL
, D BIGINT NOT NULL
);
INSERT INTO #SomeTest (A, B, C, D)
SELECT o1.object_id, o2.object_id, o3.object_id, o4.object_id
FROM sys.objects o1
, sys.objects o2
, sys.objects o3
, sys.objects o4;
SELECT COUNT(1)
FROM #SomeTest;
Это возвращает подсчет 260 144 641 на моей машине.
Чтобы проверить метод «сложения», я запускаю:
CHECKPOINT 5;
DBCC FREEPROCCACHE;
DBCC DROPCLEANBUFFERS;
SET STATISTICS IO, TIME ON;
GO
SELECT COUNT(1)
FROM #SomeTest st
WHERE (st.A + st.B + st.C + st.D) = 0;
GO
SET STATISTICS IO, TIME OFF;
Вкладка сообщений показывает:
Таблица «#SomeTest». Сканирование 3, логическое чтение 1322661, физическое чтение 0, чтение с опережением 1313877, логическое чтение 1, физическое чтение 0, чтение с опережением 0.
Время выполнения SQL Server: время ЦП = 49047 мс, прошедшее время = 173451 мс.
Для теста "дискретные столбцы":
CHECKPOINT 5;
DBCC FREEPROCCACHE;
DBCC DROPCLEANBUFFERS;
SET STATISTICS IO, TIME ON;
GO
SELECT COUNT(1)
FROM #SomeTest st
WHERE st.A = 0
AND st.B = 0
AND st.C = 0
AND st.D = 0;
GO
SET STATISTICS IO, TIME OFF;
снова с вкладки сообщений:
Таблица «#SomeTest». Сканирование 3, логическое чтение 1322661, физическое чтение 0, чтение с опережением 1322661, логическое чтение LOB 0, физическое чтение LOB 0, предварительное чтение LOB чтения 0.
Время выполнения SQL Server: время ЦП = 8938 мс, прошедшее время = 162581 мс.
Из приведенной выше статистики вы можете видеть второй вариант, когда дискретные столбцы сравниваются с 0, истекшее время примерно на 10 секунд короче, а время процессора примерно в 6 раз меньше. Большая длительность моих тестов выше, в основном, является результатом чтения большого количества строк с диска. Если вы уменьшите число строк до 3 миллионов, вы увидите, что отношения остаются примерно такими же, но затраченное время заметно падает, поскольку дисковый ввод-вывод оказывает гораздо меньшее влияние.
С помощью метода «Дополнение»:
Таблица «#SomeTest». Сканирование 3, логическое чтение 15255, физическое чтение 0, чтение с опережением 0, логическое чтение с 0, физическое чтение с 0, чтение с опережением 0.
Время выполнения SQL Server: время ЦП = 499 мс, прошедшее время = 256 мс.
С помощью метода «дискретные столбцы»:
Таблица «#SomeTest». Сканирование 3, логическое чтение 15255, физическое чтение 0, чтение с опережением 0, логическое чтение с 0, физическое чтение с 0, чтение с опережением 0.
Время выполнения SQL Server: время ЦП = 94 мс, прошедшее время = 53 мс.
Что будет действительно очень важно для этого теста? Соответствующий индекс, такой как:
CREATE INDEX IX_SomeTest ON #SomeTest(A, B, C, D);
Метод «сложения»:
Таблица «#SomeTest». Сканирование 3, логическое чтение 14235, физическое чтение 0, чтение с опережением 0, логическое чтение с 0, физическое чтение с 0, чтение с опережением 0.
Время выполнения SQL Server: время ЦП = 546 мс, прошедшее время = 314 мс.
Метод «дискретных столбцов»:
Таблица «#SomeTest». Сканирование 1, логическое чтение 3, физическое чтение 0, чтение с опережением 0, логическое чтение с бита 0, физическое чтение с бита 0, чтение с опережением чтения 0.
Время выполнения SQL Server: время ЦП = 0 мс, прошедшее время = 0 мс.
План выполнения для каждого запроса (с указанным индексом на месте) довольно показателен.
Метод сложения, который должен выполнить сканирование всего индекса:
и метод «дискретных столбцов», который может искать первую строку индекса, где находится ведущий столбец индекса A
, равен нулю: