У своєму запитанні ви докладно описуєте деякі тести, які ви підготували, де ви «докажете», що варіант додавання швидше, ніж порівняння дискретних стовпців. Я підозрюю, що ваша методологія тестування може бути помилкою в декількох напрямках, як нагадали @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, логічне зчитування лобі 0, лобічне фізичне зчитування 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, лобічне логічне зчитування 0, лобічне фізичне зчитування 0, лобічне зчитування вперед-зчитування 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
, дорівнює нулю: