Я создал команду SQL, которая использует ВНУТРЕННЕЕ ОБЪЕДИНЕНИЕ на 9 таблицах, так или иначе эта команда занимает очень долгое время (больше чем пять минут). Таким образом, мой народ предложил, чтобы я изменил ВНУТРЕННЕЕ ОБЪЕДИНЕНИЕ на ЛЕВОЕ СОЕДИНЕНИЕ, потому что производительность ЛЕВОГО СОЕДИНЕНИЯ лучше, несмотря на то, что я знаю. После того, как я изменил его, скорость запроса была значительно улучшена.
Я хотел бы знать, почему ЛЕВОЕ СОЕДИНЕНИЕ быстрее, чем ВНУТРЕННЕЕ ОБЪЕДИНЕНИЕ?
Команда My SQL похожа ниже: SELECT * FROM A INNER JOIN B ON ... INNER JOIN C ON ... INNER JOIN D
и так далее
Обновление: Это - резюме моей схемы.
FROM sidisaleshdrmly a -- NOT HAVE PK AND FK
INNER JOIN sidisalesdetmly b -- THIS TABLE ALSO HAVE NO PK AND FK
ON a.CompanyCd = b.CompanyCd
AND a.SPRNo = b.SPRNo
AND a.SuffixNo = b.SuffixNo
AND a.dnno = b.dnno
INNER JOIN exFSlipDet h -- PK = CompanyCd, FSlipNo, FSlipSuffix, FSlipLine
ON a.CompanyCd = h.CompanyCd
AND a.sprno = h.AcctSPRNo
INNER JOIN exFSlipHdr c -- PK = CompanyCd, FSlipNo, FSlipSuffix
ON c.CompanyCd = h.CompanyCd
AND c.FSlipNo = h.FSlipNo
AND c.FSlipSuffix = h.FSlipSuffix
INNER JOIN coMappingExpParty d -- NO PK AND FK
ON c.CompanyCd = d.CompanyCd
AND c.CountryCd = d.CountryCd
INNER JOIN coProduct e -- PK = CompanyCd, ProductSalesCd
ON b.CompanyCd = e.CompanyCd
AND b.ProductSalesCd = e.ProductSalesCd
LEFT JOIN coUOM i -- PK = UOMId
ON h.UOMId = i.UOMId
INNER JOIN coProductOldInformation j -- PK = CompanyCd, BFStatus, SpecCd
ON a.CompanyCd = j.CompanyCd
AND b.BFStatus = j.BFStatus
AND b.ProductSalesCd = j.ProductSalesCd
INNER JOIN coProductGroup1 g1 -- PK = CompanyCd, ProductCategoryCd, UsedDepartment, ProductGroup1Cd
ON e.ProductGroup1Cd = g1.ProductGroup1Cd
INNER JOIN coProductGroup2 g2 -- PK = CompanyCd, ProductCategoryCd, UsedDepartment, ProductGroup2Cd
ON e.ProductGroup1Cd = g2.ProductGroup1Cd
A LEFT JOIN
абсолютно не быстрее, чем INNER JOIN
. На самом деле это медленнее; по определению внешнее соединение ( LEFT JOIN
или RIGHT JOIN
) должно выполнять всю работу INNER JOIN
плюс дополнительную работу по расширению нулями полученные результаты. Также ожидается возврат большего количества строк, что еще больше увеличит общее время выполнения просто из-за большего размера набора результатов.
(И даже если ЛЕВОЕ СОЕДИНЕНИЕ
было быстрее в конкретных ситуациях из-за некоторого трудновообразимого сочетания факторов, оно функционально не эквивалентно INNER JOIN
, поэтому вы не можете просто заменить все экземпляры одного на другой!)
Скорее всего, ваши проблемы с производительностью кроются в другом месте, например, в том, что ключ кандидата или внешний ключ не проиндексированы должным образом. 9 столов - это довольно много, поэтому замедление может быть практически любым. Если вы опубликуете свою схему, мы сможем предоставить более подробную информацию.
Редактировать:
Размышляя дальше, я мог придумать одно обстоятельство, при котором ЛЕВОЕ СОЕДИНЕНИЕ
могло быть быстрее, чем ВНУТРЕННЕЕ СОЕДИНЕНИЕ
, и это когда:
Рассмотрим следующий пример:
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
вместо Имя
, и вы увидите совсем другую историю. В этом случае он выполняет вложенные циклы для обоих запросов, но версия INNER JOIN
может заменить одно из сканирований кластеризованного индекса поиском - это означает, что это будет буквально на порядок величины. быстрее при большом количестве строк.
Итак, вывод примерно такой, о чем я упоминал несколькими абзацами выше; это почти наверняка проблема индексации или покрытия индекса, возможно, в сочетании с одной или несколькими очень маленькими таблицами. Это единственные обстоятельства, при которых SQL Server может иногда выбирать худший план выполнения для INNER JOIN
, чем LEFT JOIN
.
Проблемы с производительностью, скорее всего, связаны с количеством выполняемых вами объединений и наличием индексов у столбцов, к которым вы присоединяетесь.
В худшем случае вы могли бы легко выполнять 9 сканирований всей таблицы для каждого соединения.