Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Производителност INNER JOIN срещу LEFT JOIN в SQL Server

A LEFT JOIN е абсолютно не по-бързо от INNER JOIN . Всъщност е по-бавно; по дефиниция външно присъединяване (LEFT JOIN или RIGHT JOIN ) трябва да свърши цялата работа на INNER JOIN плюс допълнителната работа за нулево удължаване на резултатите. Също така се очаква да върне повече редове, допълнително увеличавайки общото време за изпълнение просто поради по-големия размер на набора от резултати.

(И дори ако LEFT JOIN бяха по-бързо в конкретни ситуации, дължащи се на някакво трудно за представяне сливане на фактори, не е функционално еквивалентно на INNER JOIN , така че не можете просто да замените всички екземпляри на едното с друго!)

Най-вероятно проблемите ви с производителността се крият другаде, като например липсата на правилно индексиран ключ кандидат или външен ключ. 9 маси е доста, за да се присъедините, така че забавянето може да бъде буквално навсякъде. Ако публикувате своята схема, може да успеем да предоставим повече подробности.

Редактиране:

Разсъждавайки по-нататък върху това, бих могъл да се сетя за едно обстоятелство, при което LEFT JOIN може да е по-бързо от INNER JOIN , и това е когато:

  • Някои от таблиците са много малък (да речем, под 10 реда);
  • Таблиците нямат достатъчно индекси, за да покрият заявката.

Помислете за този пример:

CREATE TABLE #Test1
(
    ID int NOT NULL PRIMARY KEY,
    Name varchar(50) NOT NULL
)
INSERT #Test1 (ID, Name) VALUES (1, 'One')
INSERT #Test1 (ID, Name) VALUES (2, 'Two')
INSERT #Test1 (ID, Name) VALUES (3, 'Three')
INSERT #Test1 (ID, Name) VALUES (4, 'Four')
INSERT #Test1 (ID, Name) VALUES (5, 'Five')

CREATE TABLE #Test2
(
    ID int NOT NULL PRIMARY KEY,
    Name varchar(50) NOT NULL
)
INSERT #Test2 (ID, Name) VALUES (1, 'One')
INSERT #Test2 (ID, Name) VALUES (2, 'Two')
INSERT #Test2 (ID, Name) VALUES (3, 'Three')
INSERT #Test2 (ID, Name) VALUES (4, 'Four')
INSERT #Test2 (ID, Name) VALUES (5, 'Five')

SELECT *
FROM #Test1 t1
INNER JOIN #Test2 t2
ON t2.Name = t1.Name

SELECT *
FROM #Test1 t1
LEFT JOIN #Test2 t2
ON t2.Name = t1.Name

DROP TABLE #Test1
DROP TABLE #Test2

Ако изпълните това и прегледате плана за изпълнение, ще видите, че INNER JOIN заявката наистина струва повече от LEFT JOIN , защото отговаря на двата критерия по-горе. Това е, защото SQL Server иска да направи хеш съвпадение за INNER JOIN , но прави вложени цикли за LEFT JOIN; първото е нормално много по-бързо, но тъй като броят на редовете е толкова малък и няма индекс за използване, операцията по хеширане се оказва най-скъпата част от заявката.

Можете да видите същия ефект, като напишете програма на любимия си език за програмиране, за да извършите голям брой търсения в списък с 5 елемента, в сравнение с хеш таблица с 5 елемента. Поради размера версията на хеш таблицата всъщност е по-бавна. Но увеличете го до 50 елемента или 5000 елемента и версията на списъка ще се забави до обхождане, защото е O(N) срещу O(1) за хеш таблицата.

Но променете тази заявка да бъде на ID колона вместо Name и ще видите съвсем различна история. В този случай той прави вложени цикли и за двете заявки, но INNER JOIN версията може да замени едно от клъстерираните сканирания индекси с търсене - което означава, че това ще бъде буквално порядък на величина по-бързо с голям брой редове.

Така че заключението е горе-долу това, което споменах няколко параграфа по-горе; това почти сигурно е проблем с индексирането или покритието на индекса, вероятно комбиниран с една или повече много малки таблици. Това са единствените обстоятелства, при които SQL Server може понякога изберете по-лош план за изпълнение за INNER JOIN отколкото LEFT JOIN .



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Използване на транзакция ROLLBACK в SQL Server

  2. Как да вмъкнете C# списък в база данни с помощта на Dapper.NET

  3. Създайте изчислена колона, която използва данни от друга таблица в SQL Server

  4. 10 SP_EXECUTESQL Трябва да избягвате за по-добър динамичен SQL

  5. Пример за sys.dm_sql_referenced_entities() на SQL Server, връщащ обект, който препраща към свързан сървър