SQL Server: как сделать этот запрос более эффективным / быстрым?

Вопрос к мастерам и мастерам SQL. Я должен сократить время казни этого зверя. На выполнение требуется 5+ минут, а иногда и время ожидания. Мне нужна помощь в понимании того, как сделать его более эффективным. Я возвращаю около 100 000 строк.

Сценарий такой: я пытаюсь определить «действительные заказы», ​​которые следует пометить для чего-то, что называется «сезоном знакомств». Эти заказы будут иметь элементы, связанные с действительными «кодами категорий» (dbo.DTITEMS ON od.CATEGORY = dbo.DTITEMS.CATEGORY).

Затем я использую результаты этого запроса, чтобы в основном обновить поле заказа «DTGSEASON» со значением текущего «сезона знакомств».

Я ссылаюсь на таблицу DATING (отдельно от CRM.Dbo.Dating), в которой хранятся такие параметры, как даты начала и окончания акции, текущий сезон знакомств и т. д.

Вот запрос, который я выполняю, чтобы найти "Действительные заказы", который называется vDatingValidOrdersReg:

SELECT     
      h.CUSTOMER
    , h.ORDNUMBER
    , h.INVNETWTX
    , dtgseason.VALUE AS dtgseason
    , c.comp_dqdatingmin
    , dbo.DTITEMS.ALTMINIMUM
    , d.dat_datingapprovedon
    , d.dat_ordsincepromostart
    , h.EXPDATE
    , dbo.DATING.PROMOSTART
    , d.dat_season
    , d.dat_year
    , od.ITEM
    , od.CATEGORY
    , d.dat_DatingID
    , c.Comp_Name
    , d.dat_state
    , h.ORDUNIQ
    , c.comp_dqdatingmax
FROM CRM.dbo.Dating AS d 
INNER JOIN CRM.dbo.Company AS c 
    ON d.dat_CompanyId = c.Comp_CompanyId 
LEFT OUTER JOIN dbo.OEORDH AS h 
    ON c.Comp_IdCust = h.CUSTOMER 
LEFT OUTER JOIN dbo.OEORDHO AS dtgseason 
    ON h.ORDUNIQ = dtgseason.ORDUNIQ AND dtgseason.OPTFIELD = 'dtgseason'
INNER JOIN dbo.OEORDD AS od 
    ON h.ORDUNIQ = od.ORDUNIQ 
INNER JOIN dbo.DTITEMS 
    ON od.CATEGORY = dbo.DTITEMS.CATEGORY 
INNER JOIN dbo.DATING 
    ON d.dat_season = dbo.DATING.SEASON 
    AND d.dat_year = dbo.DATING.YEAR 
    AND dbo.DTITEMS.SEASON = dbo.DATING.SEASON 
    AND dbo.DTITEMS.YEAR = dbo.DATING.YEAR
WHERE (h.ORDDATE BETWEEN dbo.DATING.PROMOSTART AND dbo.DATING.PROMOEND) 
    AND (h.EXPDATE BETWEEN dbo.DATING.EXPSHIPST AND dbo.DATING.EXPSHIPEND) 
    AND (d.dat_state = 'Approve') 
    AND (d.dat_Deleted IS NULL) 
    AND (dbo.DATING.SEASCLOSED = 0) 
    AND (dbo.DTITEMS.ALTMINIMUM = 0) 
    AND (h.ORDNUMBER NOT IN (
                             SELECT     ORDNUMBER
                             FROM       dbo.vDatingValidOrdersAlt)) 
    AND (dbo.DATING.ORDERON = 1)

Вот запрос, на который он ссылается, который по сути является одним и тем же, но ищет заказы с разными категориями элементов: vDatingValidOrdersAlt. Это моя проблема?

SELECT     
    h.CUSTOMER
    , h.ORDNUMBER
    , h.INVNETWTX
    , dtgseason.VALUE AS dtgseason
    , c.comp_dqdatingmin
    , dbo.DTITEMS.ALTMINIMUM
    , d.dat_datingapprovedon
    , d.dat_ordsincepromostart
    , h.EXPDATE
    , dbo.DATING.PROMOSTART
    , d.dat_season
    , d.dat_year
    , od.ITEM
    , od.CATEGORY
    , d.dat_DatingID
    , c.Comp_Name
    , d.dat_state
    , h.ORDUNIQ, c.comp_dqdatingmax
FROM CRM.dbo.Dating AS d 
INNER JOIN CRM.dbo.Company AS c 
    ON d.dat_CompanyId = c.Comp_CompanyId 
LEFT OUTER JOIN dbo.OEORDH AS h 
    ON c.Comp_IdCust = h.CUSTOMER 
LEFT OUTER JOIN dbo.OEORDHO AS dtgseason 
    ON h.ORDUNIQ = dtgseason.ORDUNIQ AND dtgseason.OPTFIELD = 'dtgseason' 
INNER JOIN dbo.OEORDD AS od 
    ON h.ORDUNIQ = od.ORDUNIQ 
INNER JOIN dbo.DTITEMS 
    ON od.CATEGORY = dbo.DTITEMS.CATEGORY 
INNER JOIN dbo.DATING 
    ON d.dat_season = dbo.DATING.SEASON 
    AND d.dat_year = dbo.DATING.YEAR 
    AND dbo.DTITEMS.SEASON = dbo.DATING.SEASON 
    AND dbo.DTITEMS.YEAR = dbo.DATING.YEAR
WHERE (h.ORDDATE BETWEEN dbo.DATING.PROMOSTART AND dbo.DATING.PROMOEND) 
    AND (h.EXPDATE BETWEEN dbo.DATING.EXPSHIPST AND dbo.DATING.EXPSHIPEND)
    AND (d.dat_state = 'Approve') 
    AND (d.dat_Deleted IS NULL) 
    AND (dbo.DATING.SEASCLOSED = 0) 
    AND (dbo.DTITEMS.ALTMINIMUM > 0) 
    AND (dbo.DATING.ORDERON = 1)

Должен быть способ сделать этот запрос менее ресурсоемким, но я не знаю, как это сделать. Мысли и предложения?

Пожалуйста, подумайте о том, чтобы лучше использовать пробелы при форматировании ваших запросов. Эти запросы очень трудно читать, так как все они собраны в несколько строк. По мере выполнения запроса. вам нужно будет предоставить DDL для таблиц, индексов, а также план запроса. Мы не сможем рассказать вам, как эффективно улучшить запрос без всего этого.

Larnu 01.05.2018 16:27

Кроме того, в вашем запросе есть несколько LEFT OUTER JOIN, однако следует ссылаться на объект в вашем WHERE (например, h.EXPDATE). Это неявно превращает LEFT OUTER JOIN в INNER JOIN. Это предназначено? Если это так, вам следует использовать INNER JOIN, если нет, вам необходимо обратиться к вашим пунктам WHERE или ON ..

Larnu 01.05.2018 16:30

@Larnu Я пробовал ... изменить: похоже, Шон Ланге тоже попытался форматировать, ха-ха.

Jacob H 01.05.2018 16:47

@JacobH это намного лучше, чем было. Теперь нам просто нужно дождаться DDL, плана запроса, деталей индекса и того, почему OP ссылается на объекты, которые имеют LEFT JOIN в предложении WHERE, с предложением OR и выражением IS NULL; это означает, что это больше не LEFT JOIN. Достаточно много вопросов, на которые им нужно ответить. :)

Larnu 01.05.2018 16:50

Если этот второй запрос является представлением, которое вы выбираете в первом запросе, вы делаете нет, чтобы вернуть любой столбец, кроме ORDNUMBER. Это простое увеличение производительности прямо здесь. Я бы сделал вторичное представление, которое возвращает только один столбец для вашего предложения NOT IN.

Jacob H 01.05.2018 16:52
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
0
5
56
1

Ответы 1

У вас есть логическая проблема в обоих этих запросах. У вас есть левое соединение с dbo.OEORDH, но в этой таблице есть предложение where. Это логически меняет ваше левое соединение на внутреннее соединение. Что касается производительности, я не вижу ничего бросающегося в глаза, что вы можете изменить в своем sql. Однако я был бы удивлен, если бы у вас были индексы, подходящие для этих запросов. Нам нужно будет увидеть определение таблицы и индексы. Кроме того, решающее значение для выяснения этого будет иметь публикация планов выполнения.

Вот как могут выглядеть эти два запроса с некоторым форматированием.

SELECT h.CUSTOMER
    , h.ORDNUMBER
    , h.INVNETWTX
    , dtgseason.VALUE AS dtgseason
    , c.comp_dqdatingmin
    , di.ALTMINIMUM
    , d.dat_datingapprovedon
    , d.dat_ordsincepromostart
    , h.EXPDATE
    , dd.PROMOSTART
    , d.dat_season
    , d.dat_year
    , od.ITEM
    , od.CATEGORY
    , d.dat_DatingID
    , c.Comp_Name
    , d.dat_state
    , h.ORDUNIQ
    , c.comp_dqdatingmax
FROM CRM.dbo.Dating AS d 
INNER JOIN CRM.dbo.Company AS c ON d.dat_CompanyId = c.Comp_CompanyId 
LEFT OUTER JOIN dbo.OEORDH AS h ON c.Comp_IdCust = h.CUSTOMER 
LEFT OUTER JOIN dbo.OEORDHO AS dtgseason ON h.ORDUNIQ = dtgseason.ORDUNIQ 
                                        AND dtgseason.OPTFIELD = 'dtgseason' 
INNER JOIN dbo.OEORDD AS od ON h.ORDUNIQ = od.ORDUNIQ 
INNER JOIN dbo.DTITEMS di ON od.CATEGORY = di.CATEGORY 
INNER JOIN dbo.DATING dd ON d.dat_season = dd.SEASON 
                        AND d.dat_year = dd.YEAR 
                        AND di.SEASON = dd.SEASON 
                        AND di.YEAR = dd.YEAR
WHERE h.ORDDATE BETWEEN dd.PROMOSTART AND dd.PROMOEND
    AND h.EXPDATE BETWEEN dd.EXPSHIPST AND dd.EXPSHIPEND
    AND d.dat_state = 'Approve'
    AND d.dat_Deleted IS NULL
    AND dd.SEASCLOSED = 0
    AND di.ALTMINIMUM = 0
    AND h.ORDNUMBER NOT IN (SELECT ORDNUMBER FROM dbo.vDatingValidOrdersAlt)
    AND dd.ORDERON = 1

И второй.

SELECT h.CUSTOMER
    , h.ORDNUMBER
    , h.INVNETWTX
    , dtgseason.VALUE AS dtgseason
    , c.comp_dqdatingmin
    , di.ALTMINIMUM
    , d.dat_datingapprovedon
    , d.dat_ordsincepromostart
    , h.EXPDATE
    , dd.PROMOSTART
    , d.dat_season
    , d.dat_year
    , od.ITEM
    , od.CATEGORY
    , d.dat_DatingID
    , c.Comp_Name
    , d.dat_state
    , h.ORDUNIQ
    , c.comp_dqdatingmax
FROM CRM.dbo.Dating AS d 
INNER JOIN CRM.dbo.Company AS c ON d.dat_CompanyId = c.Comp_CompanyId 
LEFT OUTER JOIN dbo.OEORDH AS h ON c.Comp_IdCust = h.CUSTOMER 
LEFT OUTER JOIN dbo.OEORDHO AS dtgseason ON h.ORDUNIQ = dtgseason.ORDUNIQ 
                                        AND dtgseason.OPTFIELD = 'dtgseason' 
INNER JOIN dbo.OEORDD AS od ON h.ORDUNIQ = od.ORDUNIQ 
INNER JOIN dbo.DTITEMS as di ON od.CATEGORY = di.CATEGORY 
INNER JOIN dbo.DATING as dd ON d.dat_season = dd.SEASON 
                            AND d.dat_year = dd.YEAR 
                            AND di.SEASON = dd.SEASON 
                            AND di.YEAR = dd.YEAR
WHERE h.ORDDATE BETWEEN dd.PROMOSTART AND dd.PROMOEND
    AND h.EXPDATE BETWEEN dd.EXPSHIPST AND dd.EXPSHIPEND
    AND d.dat_state = 'Approve'
    AND d.dat_Deleted IS NULL
    AND dd.SEASCLOSED = 0
    AND di.ALTMINIMUM > 0
    AND dd.ORDERON = 1

Спасибо за все до сих пор. Похоже, мне нужно изменить соединение LEFT OUTER с OEORDH на соединение INNER и обновить представление vDatingValidOrdersAlt, чтобы вернуть только значение ORDNUMBER. У меня есть предполагаемый план выполнения, но он был слишком длинным для вставки здесь в формате XML - есть ли лучший способ показать его?

SQL Learner 01.05.2018 18:20

@SQLLearner Есть Google "Вставить план"

Larnu 01.05.2018 18:49

Другие вопросы по теме