微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

即使在 SQL

如何解决即使在 SQL

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

解决方法

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

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

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

预先警告,除第一项之外的任何内容都涉及动态 SQL,并且需要足够的 SQL 专业知识才能了解安全后果(SQL 注入等)和 how to deal with them。此外,您在此列表中越往下,您将需要越高级的技术技能和 SQL 知识来实施这些。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。