Вопрос к мастерам и мастерам 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)
Должен быть способ сделать этот запрос менее ресурсоемким, но я не знаю, как это сделать. Мысли и предложения?
Кроме того, в вашем запросе есть несколько LEFT OUTER JOIN
, однако следует ссылаться на объект в вашем WHERE
(например, h.EXPDATE
). Это неявно превращает LEFT OUTER JOIN
в INNER JOIN
. Это предназначено? Если это так, вам следует использовать INNER JOIN
, если нет, вам необходимо обратиться к вашим пунктам WHERE
или ON
..
@Larnu Я пробовал ... изменить: похоже, Шон Ланге тоже попытался форматировать, ха-ха.
@JacobH это намного лучше, чем было. Теперь нам просто нужно дождаться DDL, плана запроса, деталей индекса и того, почему OP ссылается на объекты, которые имеют LEFT JOIN
в предложении WHERE
, с предложением OR
и выражением IS NULL
; это означает, что это больше не LEFT JOIN
. Достаточно много вопросов, на которые им нужно ответить. :)
Если этот второй запрос является представлением, которое вы выбираете в первом запросе, вы делаете нет, чтобы вернуть любой столбец, кроме ORDNUMBER
. Это простое увеличение производительности прямо здесь. Я бы сделал вторичное представление, которое возвращает только один столбец для вашего предложения NOT IN
.
У вас есть логическая проблема в обоих этих запросах. У вас есть левое соединение с 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 - есть ли лучший способ показать его?
@SQLLearner Есть Google "Вставить план"
Пожалуйста, подумайте о том, чтобы лучше использовать пробелы при форматировании ваших запросов. Эти запросы очень трудно читать, так как все они собраны в несколько строк. По мере выполнения запроса. вам нужно будет предоставить DDL для таблиц, индексов, а также план запроса. Мы не сможем рассказать вам, как эффективно улучшить запрос без всего этого.