1

我有一个超过 300,000 行的存储过程,这是我第一次处理这种大小的东西。这是我正在编写的代码示例:

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 语句,这需要大约半小时,所以我希望找到解决这个问题的方法

4

1 回答 1

0

是的,正如评论中提到的,SQL Server 的 T-SQL 编译器是一个真正的编译器,它试图像客户端语言编译器一样编译每一行(一些客户端语言编译器有编译器指令来解决这个问题,T-SQL 有不同的技术和功能来实现下面详述的相同目的)。

如果您只想编译某些行,那么您将需要使用不同的方法。由于您的存储过程有 300,000 行,这似乎是一个非常好的主意。以下是您可能会考虑的一些技术:

  • 将其分解为具有所有决策(或更高级别决策)的主存储过程和许多具有实际 SQL 查询(和/或较低级别决策)的从属存储过程
  • 较低级别的动态 SQL。动态 SQL 直到在运行时被显式调用才被编译(SSMS 脚本程序使用这样的技术,因此您可以查看它的示例,另一个示例是包罗万象的查询
  • 使用表驱动的代码生成来自动创建适当的 SQL 代码作为预编译器阶段,实现一种或两种或上述技术
  • 使用表驱动代码生成,仅动态创建运行时需要的 SQL 代码,然后动态执行它
  • 前述技术的任何或所有组合

请注意,除了第一个项目符号之外的任何内容都涉及动态 SQL,并且需要足够的 SQL 专业知识来了解安全后果(SQL 注入等)以及如何处理它们。此外,您越往下走,实现这些所需的技术技能和 SQL 知识就越先进。

于 2021-06-21T12:43:17.353 回答