使用子查询的SQL Server慢速查询

时间:2017-11-30 19:16:09

标签: sql sql-server

我有一个非常slooowwwww查询。

它选择具有组合标准的客户记录,有点像这样:

表格有Customers,另一个表格有CustomerCars,另一个表格有CustomerMotorcycles

客户可以拥有一辆或多辆汽车。如果客户是商业企业,并且任何一个客户的汽车都是福特汽车,那么我们希望从我们的选择中排除该客户。

客户也可以拥有一辆或多辆摩托车,如果客户是零售企业且其任何一辆摩托车是哈雷,那么我们希望将该客户排除在外。

所以我有一个声明:

SELECT * 
FROM CUST
WHERE 
    (CUST.CUSTTYPE = 'COMM' 
     AND CUST.CUSTID NOT IN (SELECT CUSTCARS.CUSTID 
                             FROM CUSTCARS 
                             WHERE CUSTCARS.CAR = 'FORD'))
    OR
    (CUST.CUSTTYPE = 'RETAIL' 
     AND CUST.CUSTID NOT IN (SELECT CUSTCYCLES.CUSTID 
                             FROM CUSTCYCLES 
                             WHERE CUSTCYCLES.CYCLE = 'HARLEY'))

这很疯狂。

这当前是作为一堆将数据转储到临时表中的单独查询运行的,然后运行其他几个查询来删除我们不想要的记录,但它非常笨拙。

有什么建议吗?谢谢你的帮助!

3 个答案:

答案 0 :(得分:1)

尝试"离开连接",我们离开加入匹配我们不想要的条件的数据,然后通过where子句排除匹配的行:

SELECT
      CUST.*
FROM CUST
LEFT JOIN CUSTCARS ON CUST.CUSTID = CUSTCARS.CUSTID
      AND CUSTCARS.CAR = 'FORD'
      AND CUST.CUSTTYPE = 'COMM'
LEFT JOIN CUSTCYCLES ON CUST.CUSTID = CUSTCYCLES.CUSTID
      AND  CUSTCYCLES.CYCLE = 'HARLEY'
      AND CUST.CUSTTYPE = 'RETAIL'
WHERE CUSTCARS.CUSTID IS NULL
OR CUSTCYCLES.CUSTID IS NULL
;

虽然我在这里,但现有查询中的OR可能导致过度缓慢(可能),因此将2个子查询组合到一个列表中可能会有所帮助:

SELECT
      *
FROM CUST
WHERE CUSTID NOT IN (
      SELECT
            CUSTCARS.CUSTID
      FROM CUSTCARS
      INNER JOIN CUST ON CUSTCARS.CUSTID = CUST.CUSTID
      WHERE CUSTCARS.CAR = 'FORD'
      AND CUST.CUSTTYPE = 'COMM'
      UNION ALL
      SELECT
            CUSTCYCLES.CUSTID
      FROM CUSTCYCLES
      INNER JOIN CUST ON CUSTCYCLES.CUSTID = CUST.CUSTID
      WHERE CUSTCYCLES.CYCLE = 'HARLEY'
      AND CUST.CUSTTYPE = 'RETAIL'
      )
;

答案 1 :(得分:0)

我建议从not exists开始:

select c.*
from cust c
where not (c.custtype = 'COMM' and
           exists (select 1
                   from custcars cc
                   where cc.custid =c.custid and cc.car = 'FORD'
                  )
          ) and
      not (c.custtype = 'RETAIL' and
           exists (select 1
                   from custcycles cc
                   where cc.custid = c.custid and cc.cycle = 'HARLEY'
                  )
          ) ;

然后,您要确保在custcar(custid, car)custcycles(custid, cycle)上有索引。

答案 2 :(得分:0)

有两件事情浮现在脑海中。首先,确保有CUSTCARS.CAR和CUSTCYCLES.CYCLE的索引。其次,您可以尝试NOT EXISTS而不是NOT IN。

SELECT * FROM CUST
WHERE 
(CUST.CUSTTYPE = 'COMM' 
 AND NOT EXISTS(SELECT 1 FROM CUSTCARS WHERE CUSTCARS.CAR = 'FORD' 
                AND CUSTCARS.CUSTID=CUST.CUSTID))

OR

(CUST.CUSTTYPE = 'RETAIL' 
 AND NOT EXISTS(SELECT 1 FROM CUSTCYCLES WHERE CUSTCYCLES.CYCLE = 'HARLEY'
                AND CUSTCYCLES.CUSTID=CUST.CUSTID))