Чи є різниця у виконанні між умовою JOIN та умовою WHERE?


17

Чи є різниця в ефективності між цими двома прикладними запитами?

Запит 1:

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
where  b.tag = 'Y'

Запит 2;

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
   and b.tag = 'Y'

Зауважте, єдиною різницею є розміщення додаткової умови; перший використовує WHEREпункт, а другий додає умову до ONпункту.

Коли я запускаю ці запити в своїй системі Teradata, плани пояснення ідентичні, і крок ПРИЄДНАЙТЕ показує додаткову умову в кожному випадку. Однак на це питання щодо MySQL, одна з відповідей підказує, що другий стиль є кращим, оскільки WHEREобробка відбувається після того, як з'єднання здійснюються.

Чи слід керуватися загальним правилом при кодуванні таких запитів? Я здогадуюсь, що він повинен залежати від платформи, оскільки це, очевидно, не має ніякої різниці в моїй базі даних, але, можливо, це лише особливість Teradata. І якщо це платформа залежить, я б дуже хотів , щоб отримати кілька посилань документації; Я справді не знаю, що шукати.


9
Це залежить від платформи, оскільки це залежить від того, як оптимізатор RDBMSes справляється з розбором та оптимізацією.
Philᵀᴹ

8
І ця відповідь у пов'язаному питанні заслуговує кількох зворотних запитань. Навіть примітивний оптимізатор MySQL зрозумів би, що ці прості запити еквівалентні і що "пункт WHERE оцінюється після того, як всі з'єднання здійснені" вірно лише на логічному рівні, а не в реальному виконанні.
ypercubeᵀᴹ

1
Насправді не дублікат; це питання та відповіді порівнювали синтаксис "неявна" проти "явного" ПРИЄДНАЙТЕСЬ. Я запитую конкретно про додаткові умови приєднання.
BellevueBob

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

Відповіді:


14

Відповідно до глави 9 (Парсер та оптимізатор), Саша Пачов , сторінка 172 Книги Розуміння внутрішніх справ MySQL

Розуміння внутрішніх даних MySQL

ось розбивка оцінки запиту як наступних завдань:

  • Визначте, які ключі можна використовувати для отримання записів із таблиць, і виберіть найкращу для кожної таблиці.
  • Для кожної таблиці вирішіть, чи краще сканування таблиці, ніж читання на ключі. Якщо є багато записів, які відповідають значенню ключа, переваги ключа зменшуються, а сканування таблиці стає швидшим.
  • Визначте порядок, в якому слід з'єднати таблиці, коли в запиті присутнє більше однієї таблиці.
  • Перепишіть пункти WHERE для усунення мертвого коду, зменшуючи непотрібні обчислення та змінюючи обмеження, де це можливо, щоб відкрити шлях використання ключів.
  • Виключіть невикористані таблиці із з'єднання.
  • Визначте, чи можна використовувати ключі для ORDER BYта GROUP BY.
  • Спроба спростити підзапити, а також визначити, в якій мірі їх результати можна кешувати.
  • Об’єднати перегляди (розгорніть посилання перегляду як макросу)

На цій самій сторінці написано наступне:

У термінології оптимізатора MySQL кожен запит - це набір об'єднань. Термін приєднання використовується тут ширше, ніж у командах SQL. Запит лише на одній таблиці - це вироджене приєднання. Хоча ми зазвичай не вважаємо читання записів з однієї таблиці як об'єднанням, ті ж структури та алгоритми, які використовуються при звичайних з'єднаннях, прекрасно працюють для вирішення запиту лише однією таблицею.

ЕПІЛОГ

Через наявні ключі, кількість даних та вираження запиту, MySQL Joins іноді може робити щось для власного блага (або щоб повернутися до нас) та отримати результати, яких ми не очікували і не можемо швидко пояснити.

Я писав про цю химерність раніше

оскільки оптимізатор запитів MySQL міг зробити відхилення певних ключів під час оцінки запиту.

@ Коментар Phil допоможе мені зрозуміти, як розмістити цю відповідь (+1 для коментаря @ Phil)

Коментар @ ypercube (+1 також для цього) є компактною версією моєї публікації, оскільки оптимізатор запитів MySQL примітивний. На жаль, це має бути, оскільки це стосується двигунів зовнішнього зберігання.

ВИСНОВОК

Що стосується вашого актуального питання, оптимізатор запитів MySQL визначав би показники ефективності кожного запиту, коли він виконаний

  • підрахунок рядків
  • вибір клавіш
  • масаж наборів результатів
  • О так, роблячи фактичний ПРИЄДНАЙТЕ

Ймовірно, вам доведеться примусити виконувати порядок виконання, переписавши (рефакторинг) запит

Ось перший запит, який ви дали

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
where  b.tag = 'Y';

Спробуйте переписати його, щоб спочатку оцінити ДЕЙ

select count(*)
from   table1 a
join   (select key_col from table2 where tag='Y') b
on     b.key_col=a.key_col;

Це, безумовно, змінить план ПОЯСНЕННЯ. Це може дати кращі або гірші результати.

Одного разу я відповів на питання в StackOverflow, де я застосував цю методику. ПОЯСНЕНО було жахливим, але вистава була динамітною. Це спрацювало лише через те, що присутні правильні індекси та використання LIMIT у підзапиті .

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


2
+1 за детальною інформацією, що стосується MySQL, і особливо за те, що мене обдурило вивчення різниці між "Епілогом" та "Висновком"!
BellevueBob

У моєму дописі Епілог - це підсумок.
RolandoMySQLDBA

6
@Rolando: Ви можете додати Aftermath поліпшень на оптимізаторів в останньому MariaDB (5.3 і 5.5) версії і в недавно випущеному головному MySQL (5.6) версії. Що може зробити деякі переписування непотрібними.
ypercubeᵀᴹ

1

Для Oracle, оскільки mySQL мав тривалий опис, у нас є два способи використання оптимізатора високого рівня.

По-перше, це оптимізація на основі правил (або RBO). Oracle має 15 правил встановлення каменя, які кожен запит, який він аналізує, намагається виконувати у встановленому порядку. Якщо він не може генерувати оптимізований запит з правила 1, він рухатиметься вперед до правила 2 і вперед, поки не потрапить на правило 15.

для отримання додаткової інформації: https://docs.oracle.com/cd/B10500_01/server.920/a96533/rbo.htm

Вони впливають на ядра Oracle RDBMS від 11.1 і нижче, які не були перетворені в оптимізатор витрат на основі витрат (він же CBO). Для Oracle 11.2 і новіших версій потрібен оптимізатор CBO, але він може змусити конкретні ідентифікатори Sql для оптимізації за старим методом RBO, якщо користувач цього захоче.

Натомість CBO для Oracle 11.1+ складає декілька планів виконання одного і того ж ідентифікатора SQL та виконує той, що має найменші очікувані витрати. Він використовує багато логіки RBO, але аналізує статистику таблиці для створення витрат на динамічний план виконання для кожної операції, яку повинен зробити БД, щоб надати кінцевому користувачеві свої дані. Виконання сканування повних таблиць на дуже великих таблицях дійсно дорого; виконати повне сканування таблиці на столі з 10 рядів - це дешево. У РБО це вважалося рівними операціями.

для отримання додаткової інформації: https://oracle-base.com/articles/misc/cost-based-optimizer-and-database-statistics

Для вашого конкретного прикладу запиту: Oracle, швидше за все, розбере інформацію, щоб скласти різні плани виконання, і таким чином один буде технічно кращим, ніж інший. Однак це може бути мінімальною різницею. Окуляризуючи це, і Oracle RBO, і CBO хотіли б запитувати ще 1, тому що він виконує приєднання за менших умов, а потім фільтрує певний стовпець із тимчасової таблиці, яку він зробив під час з'єднання.


1

Якщо у вас є два запити, і ви думаєте, що вони еквівалентні, то може статися таке:

  1. Обидва запити мають однаковий план виконання. Це добре, і цього ми очікуємо. Будемо сподіватися, що це оптимальний план виконання запиту.
  2. існують різні плани виконання. У нас є дві підкази.

    2.1 У запитів різні плани виконання, але обидва плани працюють однаково добре. Це теж добре. Немає потреби в тому, що для еквівалентних запитів повинен формуватися той самий план. Але продуктивність повинна бути рівною. І знову сподіваємось, що це найкраще.

    2.2 У запитів різні плани виконання, і один план кращий за інший. Знову у нас є підрозділи:

    2.2.1 Плани різні, оскільки запити не рівноцінні. Тому уважно перевірте, чи справді вони рівноцінні. У вашому випадку вони дійсно рівноцінні.

    2.2.2 Плани різні, але запити рівноцінні. Це означає, що оптимізатор недостатньо дозрів. У досконалому світі з ідеальними оптимізаторами цього не повинно відбуватися. Так, так, це залежить від платформи, і ви повинні вивчити конкретні документи для платформи, щоб з’ясувати, чому це відбувається.

    2.2.3 Плани різні, запити рівноцінні, програмне забезпечення бази даних має помилку.

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