SQL使用Cross Apply使查询运行速度非常慢

时间:2015-05-30 07:42:10

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

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

以下是我的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

我无法找到可以改变和改善表现的地方。

1 个答案:

答案 0 :(得分:0)

我将您的查询更改为:

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部分内查看。