Внутрішній приєднатися проти Де


257

Чи є різниця в продуктивності (в oracle) між

Select * from Table1 T1 
Inner Join Table2 T2 On T1.ID = T2.ID

І

Select * from Table1 T1, Table2 T2 
Where T1.ID = T2.ID

?


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

12
@BlackTigerX: Різні результати? Чи були залучені зовнішні з'єднання? Тому що я не бачу, як відбудуться різні результати між посиланням на inner join ... onеквівалентні критерії приєднання в whereпункті.
Шеннон Северанс

у старій версії бази даних Oracle не існуєjoin
MajidTaheri

2
@MajidTaheri: скільки років для версії Oracle ви говорите? Будь-яка версія, підтримувана Oracle, підтримує позначення JOIN.
Джонатан Леффлер

Подивіться на загальні відповіді чи кращі практики, засновані на банальних випадках. Хотілося б побачити "повторну відповідність" із складнішими, де застереження включають декілька умов AND. Принаймні, у SQL Server є кросовер.
crokusek

Відповіді:


195

Немає! План виконання, подивіться на ці дві таблиці:

CREATE TABLE table1 (
  id INT,
  name VARCHAR(20)
);

CREATE TABLE table2 (
  id INT,
  name VARCHAR(20)
);

План виконання запиту за допомогою внутрішнього з'єднання:

-- with inner join

EXPLAIN PLAN FOR
SELECT * FROM table1 t1
INNER JOIN table2 t2 ON t1.id = t2.id;

SELECT *
FROM TABLE (DBMS_XPLAN.DISPLAY);

-- 0 select statement
-- 1 hash join (access("T1"."ID"="T2"."ID"))
-- 2 table access full table1
-- 3 table access full table2

І план виконання запиту за допомогою пункту WHERE.

-- with where clause

EXPLAIN PLAN FOR
SELECT * FROM table1 t1, table2 t2
WHERE t1.id = t2.id;

SELECT *
FROM TABLE (DBMS_XPLAN.DISPLAY);

-- 0 select statement
-- 1 hash join (access("T1"."ID"="T2"."ID"))
-- 2 table access full table1
-- 3 table access full table2

4
Я дуже хочу побачити, чи є офіційна документація від Oracle, яка говорить про це
4 Залиште Обкладинка

68

Якщо оптимізатор запитів виконує свою роботу правильно, між цими запитами не повинно бути різниці. Вони є лише двома способами вказати той же бажаний результат.


22
Так, продуктивність повинна бути однаковою. Але ВИБІР * ВІД Таблиця1, Таблиця2, ДЕ ... синтаксис ЗЛИВ!
Joel Coehoorn

2
Мені набагато простіше зрозуміти ВНУТРІШНІ ПРИЄДНАННЯ, ніж синтаксис SQL-92. Ваш пробіг може відрізнятися.
Крейг Трейдер

25
Я вважаю, що синтаксис WHERE легше читати, ніж ВНУТРІЙ JION - я здогадуюсь, що це Vegemite. Більшість людей у ​​світі, напевно, вважають це огидним, але діти, виховані в їжі, це люблять.
ScottCher

3
Vegemite справді противно, але потім я знову люблю лом. Піди розберися.
StingyJack

2
@Darryl Я думаю, що JOINs легше читати, оскільки умова приєднання до таблиць визначена тут же, а не "десь" у WHEREпункті. Я вважаю за краще резервувати WHEREобмеження набору даних (наприклад WHERE DATE > (SYSDATE - 1)), а не визначати, як таблиці співвідносяться один з одним (наприклад WHERE T1.ID = T2.ID). Для такої невеликої таблиці, як розглянутий приклад, мало значення, але для великих запитів, що містять кілька таблиць та декількох умов, я думаю, що це робить запит набагато простішим для розуміння.
ImaginaryHuman072889

61

Вони повинні бути абсолютно однаковими. Однак, як практику кодування, я вважаю за краще об'єднати. Це чітко формулює ваш намір,


8
Я згоден. Особливо, якщо ви приєднуєтесь до кількох таблиць, набагато простіше розібрати оператор select, якщо ви робите явні приєднання.
Пол Морі

13
Справді. Приєднання представляють семантичну залежність між двома наборами даних, але a, де пропонується відфільтрований набір. +1
ВісімдесятОдин об’єднайтесь

26

Використання JOINробить код простішим для читання, оскільки він сам собою пояснює.

Різниці в швидкості немає ( я щойно це перевірив ), і план виконання той же.


Дякую. Я шукав стиснення швидкості між цими двома методами.
Фархад Наваяздан

14

Я не знаю про Oracle, але знаю, що старий синтаксис застарілий у SQL Server і з часом зникне. Перш ніж я використав цей старий синтаксис у новому запиті, я би перевірив, що Oracle планує з ним робити.

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

І знову я спеціально не знаю Oracle, але я знаю, що версія SQL Server старого стилю лівого з'єднання є недоліком навіть у SQL Server 2000 і дає непослідовні результати (іноді ліве з'єднання, іноді перехресне з'єднання), тому його ніколи не повинно бути б / в. Сподіваємось, Oracle не зазнає тієї ж проблеми, але, безумовно, лівий і правий з'єднання можуть бути набагато важче правильно виразити у старому синтаксисі.

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


1
Амін брат. Геть приєднуйтесь !!
ScottCher

14

[Для бонусного бала ...]

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

Як всі інші кажуть, вони функціонально однакові, проте ПРИЄДНАЙТЕ більш чітко від заяви про наміри. Тому він може допомогти оптимізатору запитів або в поточних версіях Oracle у певних випадках (я не маю уявлення, чи є), він може допомогти оптимізатору запитів у майбутніх версіях Oracle (ніхто не має жодної ідеї), або може допомогти, якщо ви змінюєте постачальника баз даних.


2
Або ... легко змінити ВНУТРІШНІ ПРИЄДНАННЯ НА ЛІВНІ ПРИЄДНАННЯ, так що ви побачите, яке з'єднання змушує пропустити очікувані рядки. Я роблю це, тому що роблю весь запит одразу. Якщо ви коментуєте ВНУТРІШНІ ПРИЄДНАННЯ, вам начебто доведеться провести процес усунення. Це займає більше часу. Але +1 для вас, тому що це одна з моїх улюблених причин, щоб ВНУТРІШНІ ПРИЄДНАННЯ, крім читабельності!
Меттью Макпік

13

Вони логічно ідентичні, але в попередніх версіях Oracle, які прийняли синтаксис ANSI, часто виникали помилки з ним у більш складних випадках, тому іноді ви будете стикатися з опором розробників Oracle при його використанні.


Раніші версії Oracle мали помилки з цим? Як рано? Яка версія (и)?
ScottCher

У Metalink є деталі ... вони з'являються всюди.
Девід Олдрідж

7

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

Також можна уникати ненавмисних декартових продуктів, використовуючи приєднану версію.

Третій ефект - це легше читати SQL з більш простим умовою WHERE.


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

6

Не забувайте, що в Oracle, якщо атрибути ключа приєднання названі однаково в обох таблицях, ви також можете записати це як:

select *
from Table1 inner join Table2 using (ID);

У цього, звичайно, є такий самий план запитів.


Я rollbacked видання , тому що попередня редакція змінила сенс відповіді
JUAN

5

У сценарії, коли таблиці перебувають у 3-й звичайній формі, з'єднання між таблицями не повинні змінюватися. Тобто приєднуйтесь до КЛІЄНТІВ і ПЛАЩАННЯ завжди повинні залишатися однаковими.

Однак слід відрізняти з'єднання від фільтрів . Приєднання - це стосунки, а фільтри - про розділення цілого.

Деякі автори, посилаючись на стандарт (наприклад, Джим Мелтон; Алан Р. Саймон (1993). Розуміння нового SQL: Повне керівництво. Морган Кауфман. С. 11–12. ISBN 978-1-55860-245-8.) , написав про переваги прийняття синтаксису JOIN над таблицями, розділеними комами, у пункті FROM.

Я повністю згоден з цією точкою зору.

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


Внутрішній приєднатися на означає перехрестити приєднатися куди. Кома - це перехресне з'єднання з нижчим пріоритетом, ніж ключове слово. On vs "filter" не має значення для внутрішнього з'єднання. NF не мають значення для запитів. Ніщо в стандарті не сприяє приєднанню ключового слова до коми. Тривіальні оптимізації трапляються так само і де. Ця відповідь - купа помилок.
філіпсі

1) Я думаю, що @philipxy намагається сказати "В розділі" ВІД "таблиці, розділені комою, мають те саме значення, що і таблиці CROSS JOINed." Я з цим згоден. Звичайно, ви можете дотримуватися старого синтаксису, який може співіснувати з приєднаннями JOIN. Оптимізатори RDBMS чудово розберуть обидва випадки як однакові (якщо вони є рівнозначними, звичайно) і складуть той же план.
abrittaf

4

У PostgreSQL різниці точно немає - вони обидва прирівнюються до одного і того ж плану запитів. Я на 99% впевнений, що це стосується і Oracle.


2

Вони обидва внутрішніх з'єднань, які роблять те саме, в одному просто використовується новіший синтаксис ANSI.


2

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


1

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


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

0

Хоча ідентичність двох запитів здається очевидною, іноді трапляються деякі дивні речі. Я прийшов за запитом, у якого є різні плани виконання при переміщенні предиката приєднання від ПРИЄДНУЙТЬСЯ до ГДЕ в Oracle 10g (для ГДЕ план краще), але я не можу відтворити цю проблему в спрощених таблицях та даних. Я думаю, це залежить від моїх даних та статистики. Оптимізатор - це досить складний модуль і іноді він поводиться магічно.

Ось чому ми не можемо відповісти на це питання взагалі, оскільки це залежить від внутрішніх даних БД. Але ми повинні знати, що відповідь повинна бути " ніякої різниці ".


0

Я мав цю головоломку сьогодні, коли перевіряв один із вичерпних термінів нашої програми у виробництві, змінив внутрішнє з'єднання таблиці, побудованої з каналу XML на пункт «де» замість .... середній час виконання зараз становить 80 мс за 1000 страт, тоді як до середнього рівня exec було 2,2 секунди ... Основна різниця в плані виконання - це зникнення ключового пошуку ... Повідомлення, про яке ви не знаєте, поки не будете протестовані з використанням обох методів.

ура.



0

Як сказав києвік, план страти той же.

Заява JOIN лише легше читати, полегшуючи не забувати умови ON та отримання декартового продукту. Ці помилки можуть бути досить важкими для виявлення в довгих запитах, використовуючи кілька приєднань типу: SELECT * FROM t1, t2 WHERE t1.id = t2.some_field.

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

Це точно, чому використання оператора JOIN - це, безумовно, найкраща практика: краща ремонтопридатність та краща читабельність.

Більше того, якщо я добре пам’ятаю, JOIN оптимізований щодо використання пам’яті.


0

Я маю доповнення до цієї гарної відповіді :

Ось що визначається як SQL92 і SQL89 відповідно, різниці між продуктивністю між ними немає, хоча ви можете опустити слово ІННЕР ті).

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