复杂的SQL查询 - 超时

时间:2014-09-17 16:30:55

标签: sql sql-server

我有这个SQL查询:

WITH CTE(documents, pocname, pocphone, initialticketNo)
AS
(
   SELECT 
      SO.Documents, SO.POCName, SO.POCPhone,
      SUBSTRING(SO.Documents, 0, CHARINDEX('-', SO.Documents)) AS 'InitialCustomerTicket'
   FROM 
      ServiceOrder SO
   CROSS APPLY 
      (SELECT 
          COUNT(TECHNICIANTRIPDETAILID) TTL 
       FROM 
          TECHNICIANTRIPDETAIL 
       WHERE 
          SERVICEORDERID = SO.SERVICEORDERID 
          AND ISEQUIPMENTREPAIRED = 1) EQUIPMENT
   INNER JOIN  
      Contract CON ON CON.ContractId = SO.ContractId
   INNER JOIN 
      ClientProfile CP ON CP.ClientId = CON.ClientId
   WHERE 
      CP.ClientId = 20739 
      AND SO.CloseStatus = 1 
      AND equipment.ttl > 0 
      AND ISNULL(SO.DOCUMENTS,'') <> ''
)
SELECT * 
FROM cte 
WHERE initialticketNo <> ''

现在在上面的查询中,如果你看到我已经计算了一个字段initialticketno。我想在同一个表serviceorder上再次运行查询,并希望计数以initialticketno开头的每个票号。当我这样做时,它需要花费很多时间,有什么方法可以简化这个查询吗?

WITH CTE(documents,pocname,pocphone,initialticketNo)
as
(Select SO.Documents,SO.POCName,SO.POCPhone,
SUBSTRING(SO.Documents,0,CHARINDEX('-',SO.Documents)) AS 'InitialCustomerTicket'
From ServiceOrder SO
CROSS APPLY (SELECT COUNT(TECHNICIANTRIPDETAILID) TTL FROM TECHNICIANTRIPDETAIL WHERE SERVICEORDERID = SO.SERVICEORDERID AND ISEQUIPMENTREPAIRED = 1) EQUIPMENT
Inner Join Contract CON ON CON.ContractId = SO.ContractId
Inner Join ClientProfile CP ON CP.ClientId = CON.ClientId
where CP.ClientId = 20739 AND SO.CloseStatus = 1 and equipment.ttl > 0 AND ISNULL(SO.DOCUMENTS,'') <> '')
select * from cte 
cross apply (select count(serviceorderid) ttl from serviceorder so where so.documents like cte.initialticketNo + '%') as so
where initialticketNo <> '' and so.ttl > 1

PS:serviceorder表中的总记录为75k。

任何人都可以帮我这个。

3 个答案:

答案 0 :(得分:0)

我敢打赌,如果索引很慢而你的数据集很小,那么你就错过了索引。我认为这个查询会产生相同的输出,但我认为它会更有效。

   SELECT DISTINCT
      SO.Documents, SO.POCName, SO.POCPhone,
      SUBSTRING(SO.Documents, 0, CHARINDEX('-', SO.Documents)) AS 'InitialCustomerTicket'
   FROM ServiceOrder SO
   INNER JOIN Contract CON ON CON.ContractId = SO.ContractId
   INNER JOIN ClientProfile CP ON CP.ClientId = CON.ClientId
   INNER JOIN TECHNICIANTRIPDETAIL TTD ON TTD.SERVICEORDERID = SO.SERVICEORDERID 
          AND TTD.ISEQUIPMENTREPAIRED = 1
   WHERE 
      CP.ClientId = 20739 
      AND SO.CloseStatus = 1 
      AND ISNULL(SO.DOCUMENTS,'') <> ''
      and SUBSTRING(SO.Documents, 0, CHARINDEX('-', SO.Documents)) <> ''

答案 1 :(得分:0)

问题是Cross Apply。那将是每行运行该查询,因此可能是75k次。有两个交叉适用至少是坏的两倍;)

第一个查询可以像这样重写

SELECT 
      SO.Documents, SO.POCName, SO.POCPhone,
      SUBSTRING(SO.Documents, 0, CHARINDEX('-', SO.Documents)) AS 'InitialCustomerTicket'
   FROM 
      ServiceOrder SO
   join TECHNICIANTRIPDETAIL on SERVICEORDERID = SO.SERVICEORDERID AND ISEQUIPMENTREPAIRED = 1 as 'EQUIPMENT'
   INNER JOIN  
      Contract CON ON CON.ContractId = SO.ContractId
   INNER JOIN 
      ClientProfile CP ON CP.ClientId = CON.ClientId
   WHERE 
      CP.ClientId = 20739 
      AND SO.CloseStatus = 1 
      AND ISNULL(SO.DOCUMENTS,'') <> ''
   Group by SO.Documents, SO.POCName, SO.POCPhone,
      SUBSTRING(SO.Documents, 0, CHARINDEX('-', SO.Documents)) AS 'InitialCustomerTicket'
   having count(equipment.TECHNICIANTRIPDETAILID) > 0

第二个可以这样写:

 SELECT 
      SO.Documents, SO.POCName, SO.POCPhone,
      SUBSTRING(SO.Documents, 0, CHARINDEX('-', SO.Documents)) AS 'InitialCustomerTicket'
   FROM 
      ServiceOrder SO
   join TECHNICIANTRIPDETAIL on SERVICEORDERID = SO.SERVICEORDERID AND ISEQUIPMENTREPAIRED = 1 as 'EQUIPMENT'
   INNER JOIN  
      Contract CON ON CON.ContractId = SO.ContractId
   INNER JOIN 
      ClientProfile CP ON CP.ClientId = CON.ClientId
    join serviceorder as SO2 on so2.documents like so.initialticketNo + '%'
   WHERE 
      CP.ClientId = 20739 
      AND SO.CloseStatus = 1 
      AND ISNULL(SO.DOCUMENTS,'') <> ''
   Group by SO.Documents, SO.POCName, SO.POCPhone,
      SUBSTRING(SO.Documents, 0, CHARINDEX('-', SO.Documents)) AS 'InitialCustomerTicket'
   having count(equipment.TECHNICIANTRIPDETAILID) > 0
      and count(so2.serviceorderid) > 1

当然,我之前和之后都无法运行,因为我没有数据,但我认为应该这样做。如果不是,它至少可以让您知道在哪里前进 - 尽可能删除Cross Apply

答案 2 :(得分:0)

这是一个更简单且(可能更有效)的查询:

SELECT  SO.Documents ,
        SO.POCName ,
        SO.POCPhone ,
        SUBSTRING(SO.Documents, 0, CHARINDEX('-', SO.Documents)) AS initialticketNo
FROM    ClientProfile CP
        INNER JOIN [Contract] CON ON CON.ClientId = CP.ClientId
        INNER JOIN ServiceOrder SO ON SO.ContractId = CON.ContractId
WHERE   CP.ClientId = 20739
        AND SO.CloseStatus = 1
        AND SO.Documents IS NOT NULL
        AND SO.Documents LIKE '%-%'
        AND EXISTS ( SELECT *
                     FROM   TECHNICIANTRIPDETAIL TTL
                     WHERE  TTL.ISEQUIPMENTREPAIRED = 1
                     AND TTL.SERVICEORDERID = SO.SERVICEORDERID )