Продуктивність a = 0 і b = 0 і… z = 0 проти a + b + c + d = 0


20

Це просте запитання, на яке я не можу знайти відповідь.

Що стосується продуктивності, Якщо у мене є WHEREположення, такі як a=0 and b=0 and ... z=0: Чи отримав би я якісь результати, якби замінив цю умову a+b+...+z=0?

Іншими словами, чи є підвищення продуктивності, замінивши наступне

Select * 
From MyTable 
Where A=0 and B=0 and C=0 and D=0...

З

Select * 
From MyTable 
Where A+B+C+D=0...

Я знаю, що це може залежати від індексів, але для цього скажімо, що індекси не існують. Чи працює арифметичний оператор (+) краще, ніж логічний оператор "АБО" чи "І"?

Мені здається, що додавання виконує кращі показники, ніж декілька умов із AND або OR.

Результати тесту

На таблиці 4,2 ​​мільйона рядків

Повернення рядків Де А = 0 В = 0 і С = 0 -> 351748 Рядки

Додавання (A + B + C = 0) зайняло 5 секунд, тоді як логічні умови A = 0 і B = 0 і C = 0 зайняли 11 секунд.

З іншої сторони

Повернення рядків, де A <> 0 B <> 0 або C <> 0 -> 3829750 Рядки 58 секунд

Повернення рядків Де F65 + F67 + f64 <> 0 -> 3829750 Рядки 57 секунд

Для АБО здається, що суттєвої різниці немає.

Я згоден з gbn:

Якщо A дорівнює -1, а B дорівнює 1, A + B = 0, але A = 0 і B = 0 - хибне

та з AMtwo:

ABS (A) + ABS (B) + ABS (C) + ABS (D) ... Навіть якщо ви очікуєте лише позитивних значень, якщо стовпець приймає негативні значення, слід припустити, що ви можете зіткнутися з одним

Результати є дуже вражаючими, як я думав, здається, що додавання набагато швидше, ніж логічні оператори.

A = Float, B = Гроші і C = Float. Використовуваний запит, як показано на малюнку. У моєму випадку всі позитивні числа. Індексів немає. Мені просто логічно, що додавання було б швидшим, ніж Логічні умови!


Це булі? Скільки стовпців ви говорите про 4 (у прикладах) або 26 (у заголовку)? Це має значення. Яка версія SQL Server? Де грають FLOAT та MONEY? Скільки рядків ми припускаємо? Це питання має низку факторів.
Еван Керролл

@ Еван Керролл Вони не булеві, вони неіндексовані номери (int, float, гроші тощо). Незалежно від версії SQL (SQL2012 і вище), кількості рядків або стовпців. Питання полягало у тому, щоб з’ясувати, який оператор працює краще - логічний та арифметичний оператори. Як бачимо, Макс Вернон демонструє теорію своїми прикладами чудово.
JohnG

Відповіді:


46

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

введіть тут опис зображення


24

Скажімо, у вас є індекс на A, B, C і D. Можливо також фільтрувати.

Це швидше використовувати індекс, ніж додавання.

Where A=0 and B=0 and C=0 and D=0

В інших новинах: Якщо A дорівнює -1, а B - 1, A+B=0це правда, але A=0 and B=0неправда.


7

(Будь ласка, зауважте, що ця відповідь була подана до того, як будь-яке тестування було відмічено у Питання: текст Запитання закінчився трохи вище розділу Тести .)

Я б припустив, що окремі ANDумови будуть кращими, оскільки оптимізатор буде швидше замикати роботу, якщо жодна з них не дорівнює 0, не потрібно спочатку робити обчислення.

Однак, оскільки це питання продуктивності, спочатку слід встановити тест, щоб визначити відповідь на вашому обладнання. Повідомте про результати, показавши свій тестовий код, і попросіть інших переглянути його, щоб переконатися, що це хороший тест. Можуть бути й інші фактори, варті врахування, про які ви не думали.


3

Деякі загальні міркування, якщо у вас немає індексів під рукою, я не думаю, що це буде мати велике значення, яке з двох обраних вами рішень, обидва будуть працювати погано. Якщо ви, з іншого боку, маєте індекс на одному або декількох стовпцях предиката, перший, швидше за все, буде краще, ніж другий, оскільки другий, ймовірно, не зможе використовувати індекс (и).

Диз'юнкції (АБО) взагалі діють гірше, ніж кон'юнкції (І), але навіть якщо у вас є запит із диз'юнкціями, я покладу свої гроші на перший.


2

Це просте запитання

Ні, це не так. Це (своєрідне) запитання - це те, що щодня переживає багато DBA та розробників програмного забезпечення, і це не тільки тривіально.

на що я не можу знайти відповідь.

Так, ви не будете. Принаймні, не загальна відповідь. Перш за все, це дуже залежатиме від того, який RDBMS ви використовуєте (ОК, ви використовуєте , але все ж). Це навіть може змінитися, коли ви переходите від однієї версії RDBMS до іншої.

Тоді це може залежати від будь-якої кількості інших дрібних деталей, наприклад, від того, як ваша БД зберігає дані, якщо у вас є суб-вибір / приєднання, що плутають проблему для оптимізатора плану тощо. Оптимізатор може дати вам різні плани виконання залежно від на скільки рядків у вас ...

Тест у реальному світі зазвичай є єдиним корисним способом вирішення подібних питань. Крім того, будь-які надбавки, отримані завдяки "прихованим" оптимізаціям, як це, зазвичай, поглинаються вдесятеро розумним вибором індексів, тому я б не заважав витрачати на це занадто багато часу, перш ніж використання індексів справді виключено.


0

Це може бути очевидним, але якщо стовпці є INT, то вони a+b+cмогли б дорівнювати нулю, навіть коли жоден з них насправді не дорівнює нулю. Ви тестуєте дві різні речі!


Щойно зрозумів, що @gbn згадав про це у своїй відповіді.
Росс Пресер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.