ВНУТРЕННЕЕ ОБЪЕДИНЕНИЕ по сравнению с ЛЕВЫМ ПРИСОЕДИНЯЕТСЯ к производительности в SQL Server

Я создал команду 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
247
задан Saman Hakimzadeh Abyaneh 13 July 2019 в 22:27
поделиться

2 ответа

A LEFT JOIN абсолютно не быстрее, чем INNER JOIN . На самом деле это медленнее; по определению внешнее соединение ( LEFT JOIN или RIGHT JOIN ) должно выполнять всю работу INNER JOIN плюс дополнительную работу по расширению нулями полученные результаты. Также ожидается возврат большего количества строк, что еще больше увеличит общее время выполнения просто из-за большего размера набора результатов.

(И даже если ЛЕВОЕ СОЕДИНЕНИЕ было быстрее в конкретных ситуациях из-за некоторого трудновообразимого сочетания факторов, оно функционально не эквивалентно INNER JOIN , поэтому вы не можете просто заменить все экземпляры одного на другой!)

Скорее всего, ваши проблемы с производительностью кроются в другом месте, например, в том, что ключ кандидата или внешний ключ не проиндексированы должным образом. 9 столов - это довольно много, поэтому замедление может быть практически любым. Если вы опубликуете свою схему, мы сможем предоставить более подробную информацию.


Редактировать:

Размышляя дальше, я мог придумать одно обстоятельство, при котором ЛЕВОЕ СОЕДИНЕНИЕ могло быть быстрее, чем ВНУТРЕННЕЕ СОЕДИНЕНИЕ , и это когда:

  • Некоторые таблицы очень маленькие (скажем, менее 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 вместо Имя , и вы увидите совсем другую историю. В этом случае он выполняет вложенные циклы для обоих запросов, но версия INNER JOIN может заменить одно из сканирований кластеризованного индекса поиском - это означает, что это будет буквально на порядок величины. быстрее при большом количестве строк.

Итак, вывод примерно такой, о чем я упоминал несколькими абзацами выше; это почти наверняка проблема индексации или покрытия индекса, возможно, в сочетании с одной или несколькими очень маленькими таблицами. Это единственные обстоятельства, при которых SQL Server может иногда выбирать худший план выполнения для INNER JOIN , чем LEFT JOIN .

394
ответ дан 23 November 2019 в 03:02
поделиться

Проблемы с производительностью, скорее всего, связаны с количеством выполняемых вами объединений и наличием индексов у столбцов, к которым вы присоединяетесь.

В худшем случае вы могли бы легко выполнять 9 сканирований всей таблицы для каждого соединения.

8
ответ дан 23 November 2019 в 03:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: