Компилятор, кажется, оценивает каждый оператор if, даже если условия не выполняются в SQL
У меня хранимая процедура содержит чуть более 300000 строк, и я впервые работаю над чем-то такого размера. вот пример кода, который я пишу:
IF (@type = 'commande client')
AND @etat = 'ouvert'
BEGIN
IF (@tiersd = '')
AND @tiersf = ''
BEGIN
IF (@familled = '')
AND @famillef = ''
BEGIN
IF (@commerciald = '')
AND @commercialf = ''
BEGIN
IF (@articled = '')
AND @articlef = ''
BEGIN
IF (@afamilled = '')
AND @afamillef = ''
BEGIN
SELECT ordr.docentry,
OITM.itemCode,
rdr1.dscription,
rdr1.quantity,
rdr1.price,
rdr1.currency,
rdr1.slpCode,
rdr1.basedocnum,
rdr1.shiptocode,
rdr1.shiptodesc,
rdr1.baseprice,
ordr.docnum,
ordr.doctype,
ordr.docstatus,
ordr.docTotal,
ordr.docdate,
ordr.cardcode,
ordr.cardname,
ordr.address,
ordr.doccur,
ordr.paidtodate,
ordr.doctime,
ordr.docsubtype,
ordr.basetype,
ordr.baseEntry,
OITM.itemclass,
OITM.itemtype,
OITM.itemname,
OITM.itmsgrpcod
FROM ordr
INNER JOIN rdr1 ON ordr.docentry = rdr1.docentry
INNER JOIN oitm ON OITM.itemcode = rdr1.ItemCode
WHERE ordr.DocDate BETWEEN @dated AND @datef
AND DocStatus = 'o';
END;
ELSE IF (@afamilled != '')
AND @afamillef = ''
BEGIN
SELECT ordr.docentry,
OITM.itemCode,
rdr1.dscription,
rdr1.quantity,
rdr1.price,
rdr1.currency,
rdr1.slpCode,
rdr1.basedocnum,
rdr1.shiptocode,
rdr1.shiptodesc,
rdr1.baseprice,
ordr.docnum,
ordr.doctype,
ordr.docstatus,
ordr.docTotal,
ordr.docdate,
ordr.cardcode,
ordr.cardname,
ordr.address,
ordr.doccur,
ordr.paidtodate,
ordr.doctime,
ordr.docsubtype,
ordr.basetype,
ordr.baseEntry,
OITM.itemclass,
OITM.itemtype,
OITM.itemname,
OITM.itmsgrpcod
FROM ordr
INNER JOIN rdr1 ON ordr.docentry = rdr1.docentry
INNER JOIN oitm ON OITM.itemcode = rdr1.ItemCode
WHERE OITM.itmsgrpcod BETWEEN @afamilled AND ((SELECT MAX(itmsgrpcod)FROM oitm))
AND ordr.DocDate BETWEEN @dated AND @datef
AND DocStatus = 'o';
END;
ELSE IF (@afamilled = '')
AND @afamillef != ''
BEGIN
SELECT ordr.docentry,
OITM.itemCode,
rdr1.dscription,
rdr1.quantity,
rdr1.price,
rdr1.currency,
rdr1.slpCode,
rdr1.basedocnum,
rdr1.shiptocode,
rdr1.shiptodesc,
rdr1.baseprice,
ordr.docnum,
ordr.doctype,
ordr.docstatus,
ordr.docTotal,
ordr.docdate,
ordr.cardcode,
ordr.cardname,
ordr.address,
ordr.doccur,
ordr.paidtodate,
ordr.doctime,
ordr.docsubtype,
ordr.basetype,
ordr.baseEntry,
OITM.itemclass,
OITM.itemtype,
OITM.itemname,
OITM.itmsgrpcod
FROM ordr
INNER JOIN rdr1 ON ordr.docentry = rdr1.docentry
INNER JOIN oitm ON OITM.itemcode = rdr1.ItemCode
WHERE OITM.itmsgrpcod BETWEEN ((SELECT MIN(itmsgrpcod)FROM oitm)) AND @afamillef
AND ordr.DocDate BETWEEN @dated AND @datef
AND DocStatus = 'o';
END;
IF (@afamilled != '')
AND @afamillef != ''
BEGIN
SELECT ordr.docentry,
OITM.itemCode,
rdr1.dscription,
rdr1.quantity,
rdr1.price,
rdr1.currency,
rdr1.slpCode,
rdr1.basedocnum,
rdr1.shiptocode,
rdr1.shiptodesc,
rdr1.baseprice,
ordr.docnum,
ordr.doctype,
ordr.docstatus,
ordr.docTotal,
ordr.docdate,
ordr.cardcode,
ordr.cardname,
ordr.address,
ordr.doccur,
ordr.paidtodate,
ordr.doctime,
ordr.docsubtype,
ordr.basetype,
ordr.baseEntry,
OITM.itemclass,
OITM.itemtype,
OITM.itemname,
OITM.itmsgrpcod
FROM ordr
INNER JOIN rdr1 ON ordr.docentry = rdr1.docentry
INNER JOIN oitm ON OITM.itemcode = rdr1.ItemCode
WHERE OITM.itmsgrpcod BETWEEN @afamilled AND @afamillef
AND ordr.DocDate BETWEEN @dated AND @datef
AND DocStatus = 'o';
END;
END;
----------------------------
ELSE IF (@articled != '')
AND @articlef != ''
BEGIN
IF (@afamilled = '')
AND @afamillef = ''
BEGIN
SELECT ordr.docentry,
OITM.itemCode,
rdr1.dscription,
rdr1.quantity,
rdr1.price,
rdr1.currency,
rdr1.slpCode,
rdr1.basedocnum,
rdr1.shiptocode,
rdr1.shiptodesc,
rdr1.baseprice,
ordr.docnum,
ordr.doctype,
ordr.docstatus,
ordr.docTotal,
ordr.docdate,
ordr.cardcode,
ordr.cardname,
ordr.address,
ordr.doccur,
ordr.paidtodate,
ordr.doctime,
ordr.docsubtype,
ordr.basetype,
ordr.baseEntry,
OITM.itemclass,
OITM.itemtype,
OITM.itemname,
OITM.itmsgrpcod
FROM ordr
INNER JOIN rdr1 ON ordr.docentry = rdr1.docentry
INNER JOIN oitm ON OITM.itemcode = rdr1.ItemCode
WHERE OITM.itemcode BETWEEN @articled AND @articlef
AND ordr.DocDate BETWEEN @dated AND @datef
AND DocStatus = 'o';
END;
IF (@afamilled != '')
AND @afamillef = ''
BEGIN
SELECT ordr.docentry,
OITM.itemCode,
rdr1.dscription,
rdr1.quantity,
rdr1.price,
rdr1.currency,
rdr1.slpCode,
rdr1.basedocnum,
rdr1.shiptocode,
rdr1.shiptodesc,
rdr1.baseprice,
ordr.docnum,
ordr.doctype,
ordr.docstatus,
ordr.docTotal,
ordr.docdate,
ordr.cardcode,
ordr.cardname,
ordr.address,
ordr.doccur,
ordr.paidtodate,
ordr.doctime,
ordr.docsubtype,
ordr.basetype,
ordr.baseEntry,
OITM.itemclass,
OITM.itemtype,
OITM.itemname,
OITM.itmsgrpcod
FROM ordr
INNER JOIN rdr1 ON ordr.docentry = rdr1.docentry
INNER JOIN oitm ON OITM.itemcode = rdr1.ItemCode
WHERE OITM.itemcode BETWEEN @articled AND @articlef
AND OITM.itmsgrpcod BETWEEN @afamilled AND ((SELECT MAX(itmsgrpcod)FROM oitm))
AND ordr.DocDate BETWEEN @dated AND @datef
AND DocStatus = 'o';
END;
IF (@afamilled = '')
AND @afamillef != ''
BEGIN
SELECT ordr.docentry,
OITM.itemCode,
rdr1.dscription,
rdr1.quantity,
rdr1.price,
rdr1.currency,
rdr1.slpCode,
rdr1.basedocnum,
rdr1.shiptocode,
rdr1.shiptodesc,
rdr1.baseprice,
ordr.docnum,
ordr.doctype,
ordr.docstatus,
ordr.docTotal,
ordr.docdate,
ordr.cardcode,
ordr.cardname,
ordr.address,
ordr.doccur,
ordr.paidtodate,
ordr.doctime,
ordr.docsubtype,
ordr.basetype,
ordr.baseEntry,
OITM.itemclass,
OITM.itemtype,
OITM.itemname,
OITM.itmsgrpcod
FROM ordr
INNER JOIN rdr1 ON ordr.docentry = rdr1.docentry
INNER JOIN oitm ON OITM.itemcode = rdr1.ItemCode
WHERE OITM.itemcode BETWEEN @articled AND @articlef
AND OITM.itmsgrpcod BETWEEN ((SELECT MIN(itmsgrpcod)FROM oitm)) AND @afamillef
AND ordr.DocDate BETWEEN @dated AND @datef
AND DocStatus = 'o';
END;
IF (@afamilled != '')
AND @afamillef != ''
BEGIN
SELECT ordr.docentry,
OITM.itemCode,
rdr1.dscription,
rdr1.quantity,
rdr1.price,
rdr1.currency,
rdr1.slpCode,
rdr1.basedocnum,
rdr1.shiptocode,
rdr1.shiptodesc,
rdr1.baseprice,
ordr.docnum,
ordr.doctype,
ordr.docstatus,
ordr.docTotal,
ordr.docdate,
ordr.cardcode,
ordr.cardname,
ordr.address,
ordr.doccur,
ordr.paidtodate,
ordr.doctime,
ordr.docsubtype,
ordr.basetype,
ordr.baseEntry,
OITM.itemclass,
OITM.itemtype,
OITM.itemname,
OITM.itmsgrpcod
FROM ordr
INNER JOIN rdr1 ON ordr.docentry = rdr1.docentry
INNER JOIN oitm ON OITM.itemcode = rdr1.ItemCode
WHERE OITM.itemcode BETWEEN @articled AND @articlef
AND OITM.itmsgrpcod BETWEEN @afamilled AND @afamillef
AND ordr.DocDate BETWEEN @dated AND @datef
AND DocStatus = 'o';
END;
END;
проблема в том, что компилятор, кажется, проверяет внутри каждого оператора if, даже если условия не выполняются, а это занимает около получаса, поэтому я надеюсь найти решение этой проблемы.
1 ответ
Да, как упоминалось в комментариях, компилятор T-SQL SQL Server - это настоящий компилятор, который пытается скомпилировать каждую строку так же, как это делают компиляторы клиентского языка (некоторые компиляторы клиентского языка имеют директивы компилятора, чтобы обойти эту проблему, T-SQL имеет различные методы и функции для достижения той же цели, как описано ниже).
Если вы хотите, чтобы были скомпилированы только некоторые строки, вам нужно будет использовать другой подход. Поскольку ваша хранимая процедура содержит 300000 строк, в любом случае это кажется очень хорошей идеей. Вот некоторые из техник, которые вы могли бы рассмотреть:
- Разбейте его на главный sProc со всеми решениями (или решениями более высокого уровня) и множество подчиненных sProc, которые имеют фактические запросы SQL (и / или решения более низкого уровня).
- Динамический SQL для нижних уровней. Динамический SQL не компилируется до тех пор, пока он не будет явно вызван во время выполнения (скрипт SSMS использует подобные методы, поэтому вы можете поискать в нем примеры, еще один пример - универсальные запросы).
- Используйте генерацию кода на основе таблиц для автоматического создания правильного кода SQL в качестве этапа предварительной компиляции, реализуя один, оба или предыдущие методы.
- Используйте генерацию кода на основе таблиц, чтобы динамически создавать только тот код SQL, который вам нужен во время выполнения, а затем динамически выполнять его.
- Любая или все комбинации предшествующих техник.
Имейте в виду, что все, кроме первого пункта, включает динамический SQL и требует достаточных знаний SQL, чтобы понять последствия безопасности (SQL-инъекция и т. Д.) И как с ними бороться . Кроме того, чем дальше вы идете по этому списку, тем более продвинутые технические навыки и знания SQL вам понадобятся для их реализации.