【问题标题】:SQL Using Cross Apply makes the query to run very slowSQL Using Cross Apply 使查询运行非常缓慢
【发布时间】:2015-05-30 07:42:09
【问题描述】:

下面的查询需要 35 秒才能完成,所以前端应用程序抛出“超时过期”错误,我通过增加 CommandTimeOut 来修复,但我的审阅者不接受修复,因为修复必须在 sql 查询中完成。

下面是我的sql查询

select * from SamplesPartners as sp WITH (READUNCOMMITTED) WHERE (EXISTS
(
    SELECT      *
    FROM        SamplesPartners  AS sp2
    CROSS APPLY SE_GetCurrentParentContainersForItem(sp2.samplePartnerSqlId, sp2.samplePartnerIncId, 2, 293) AS CC
    JOIN        dbo.Containers   AS C ON    C.containerSqlId = CC.containerSqlId
                                        AND C.containerIncId = CC.containerIncId
                                        AND C.isDeleted      = 0x0
    LEFT JOIN   dbo.Shipments    AS S ON    S.containerSqlId = C.containerSqlId
                                        AND S.containerIncId = C.containerIncId
                                        AND S.isDeleted      = 0x0
    LEFT JOIN   dbo.Destinations AS D ON    D.containerSqlId = C.containerSqlId
                                        AND D.containerIncId = C.containerIncId
                                        AND D.isDeleted      = 0x0
    WHERE       sp2.samplePartnerSqlId = sp.samplePartnerSqlId
    AND         sp2.samplePartnerIncId = sp.samplePartnerIncId
    AND         (
                    C.containerCode   LIKE '%test%'
                OR  C.containerName   LIKE '%test%'
                OR  S.trackingNumber  LIKE '%test%'
                OR  D.destinationName LIKE '%test%'
                )   
    AND         sp2.isDeleted = 0x0
)) and isDeleted=0

下面是函数

ALTER FUNCTION [dbo].[SE_GetCurrentParentContainersForItem]
(
    @itemSqlId          SMALLINT,
    @itemIncId          INT,
    @itemMetaTableSqlId SMALLINT,
    @itemMetaTableIncId INT
)
RETURNS TABLE

AS

RETURN
WITH      ContainersMetaTable AS (
           -- Returns only 1 record.
           SELECT    metaTableSqlId,metaTableIncId FROM dbo.MetaTables WHERE metaTableName = 'Containers'),
          ContainerSubtree AS (
           -- Anchor member.
           SELECT    containerSqlId,containerIncId,0 AS lvl
           FROM      dbo.ContainersContents
           WHERE     contentSqlId          = @itemSqlId
             AND     contentIncId          = @itemIncId
             AND     contentMetaTableSqlId = @itemMetaTableSqlId
             AND     contentMetaTableIncId = @itemMetaTableIncId
             AND     isDeleted             = 0

           UNION ALL

           -- Recursive member.
           SELECT    cc.containerSqlId,
                     cc.containerIncId,
                     sub.lvl + 1        AS lvl
           FROM      ContainersMetaTable    AS cmt,
                     dbo.ContainersContents AS cc
           JOIN      ContainerSubtree       AS sub ON  cc.contentSqlId = sub.containerSqlId
                                                   AND cc.contentIncId = sub.containerIncId
                                                   AND cc.isDeleted    = 0
           WHERE     cc.contentMetaTableSqlId = cmt.metaTableSqlId
             AND     cc.contentMetaTableIncId = cmt.metaTableIncId             
          )
SELECT    containerSqlId,
          containerIncId,
          lvl
FROM      ContainerSubtree

我找不到可以改变和提高性能的地方。

【问题讨论】:

    标签: performance sql-server-2008 cross-apply


    【解决方案1】:

    我将您的查询更改为:

    SELECT * 
    FROM SamplesPartners AS sp WITH (READUNCOMMITTED) 
    WHERE (EXISTS (
        SELECT      1
        FROM        SamplesPartners  AS sp2
        CROSS APPLY SE_GetCurrentParentContainersForItem(sp2.samplePartnerSqlId, sp2.samplePartnerIncId, 2, 293) AS CC
        JOIN        dbo.Containers   AS C ON    C.containerSqlId = CC.containerSqlId
                                            AND C.containerIncId = CC.containerIncId
                                            AND C.isDeleted      = 0
        LEFT JOIN   dbo.Shipments    AS S ON    S.containerSqlId = C.containerSqlId
                                            AND S.containerIncId = C.containerIncId
                                            AND S.isDeleted      = 0
        LEFT JOIN   dbo.Destinations AS D ON    D.containerSqlId = C.containerSqlId
                                            AND D.containerIncId = C.containerIncId
                                            AND D.isDeleted      = 0
        WHERE       sp2.samplePartnerSqlId = sp.samplePartnerSqlId
        AND         sp2.samplePartnerIncId = sp.samplePartnerIncId
        AND         (C.containerCode + ':' + C.containerName + ':' + S.trackingNumber + ':' + D.destinationName) LIKE '%test%'
        AND         sp2.isDeleted = 0
        )) 
    

    我改变这个:

    • 删除 OR 运算符并合并所有 LIKE 运算符以减少对数据的搜索。
    • 使用1 作为一个字段而不是* 作为多个字段以减少内存使用。
    • 我将isDeleted = 0x0 更改为isDeleted = 0 以减少它的类型转换,因为我认为它的类型不是varbinary,因为您也在表值函数中使用它。
    • 我删除了最后一个 AND isDeleted = 0,因为您在 EXISTS 部分内检查它。

    【讨论】:

    • 删除“OR”运算符并合并所有“LIKE”运算符会得到“零”结果。即使我实施了其他两项改进,总性能时间也保持不变。
    • @Selva 删除“OR”运算符并合并所有“LIKE”运算符会给您相同的结果,第二个选项在内存限制的服务器上具有更好的性能,第三个选项我问的是isDeleted 字段的类型,它正是varbinary
    • 删除“OR”运算符并合并所有“LIKE”运算符给出零结果,相信我:) 并且“isDeleted”类型是“bit”。你提到了替换表值函数,你能详细说明一下吗?
    猜你喜欢
    • 2021-05-16
    • 1970-01-01
    • 1970-01-01
    • 2013-09-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多