很多LEFT JOIN都会导致MSSQL查询运行缓慢

时间:2013-05-01 07:10:34

标签: sql-server left-join

我正在使用mssql server 2008r2。 我有一个巨大的表格,每天包含19个商店营业额数据。它有大约1亿行。但是通过分区视图,可以轻松运行查询。

表的结构如下所示:

  1. 商店名称
  2. 项目ID
  3. 日期
  4. 周转
  5. 卖出数量
  6. 输出报告如下所示: 商品ID,日期,store_1.turnover,store_1.quantity,store_2.turnover,store_2.quantity ....

    要创建此类报告,我使用此查询:

    WITH cte_sell AS(
        SELECT * 
        FROM view_turnover 
        WHERE date BETWEEN '130413' and '130418' )
    
    SELECT a.item_id,a.date,
        store_1.turnover,store_1.quantity,
        store_2.turnover,store_2.quantity,
        store_3.turnover,store_3.quantity
    
    FROM (SELECT DISTINCT item_id,date FROM cte_sell) as a
    LEFT JOIN (SELECT * FROM cte_sell WHERE store='Store 1') as Store_1 ON a.item_id=store_1.item_id and a.date=store_1.date    
    LEFT JOIN (SELECT * FROM cte_sell WHERE store='Store 2') as Store_2 ON a.item_id=store_2.item_id and a.date=store_2.date    
    LEFT JOIN (SELECT * FROM cte_sell WHERE store='Store 3') as Store_3 ON a.item_id=store_3.item_id and a.date=store_3.date
    

    我希望你能理解这个问题。

    对于14-15商店(14 15 LEFT JOIN),查询运行时间少于10秒,这很好。 但问题是当我选择所有19个商店(19 LEFT JOIN)时,查询显着减慢。完成可能需要2到3分钟。

    执行计划的创建时间也要长得多:

    • 仅限12家商店
    • 19家商店22秒

    您如何看待,表格加入是否有任何限制? 我认为有一些服务器参数可以控制巨大的查询。 有谁知道如何优化查询或服务器?

    最糟糕的是,服务器有时会冻结:我在9点钟和12点运行查询时创建了一个跟踪文件。 9点运行查询需要2分钟。 在12点,我在1​​0分钟后重新启动了comupetr,因为我无法从配置管理器重新启动SQL服务。

    我无法附上screnshots。

    在活动监视器中,进程处于挂起状态。 等待类型是:CXPACKET 等待资源是:交换.... 对不起,但我对锁不太了解。

    我尝试从管理工作室连接并收到此消息:已成功与服务器建立连接,但在登录过程中出现错误。 (提供者:TCP提供者,错误:0(翻译自匈牙利语):远程机器强制关闭现有连接。

2 个答案:

答案 0 :(得分:1)

您是否考虑过删除子查询并仅使用连接条件?

WITH cte_sell AS(
    SELECT * 
    FROM view_turnover 
    WHERE date BETWEEN '130413' and '130418' )

SELECT a.item_id,a.date,
    store_1.turnover,store_1.quantity,
    store_2.turnover,store_2.quantity,
    store_3.turnover,store_3.quantity

FROM (SELECT DISTINCT item_id,date FROM cte_sell) as a
LEFT JOIN cte_sell as Store_1 ON a.item_id=store_1.item_id and a.date=store_1.date and Store='Store 1'
LEFT JOIN cte_sell as Store_2 ON a.item_id=store_2.item_id and a.date=store_2.date and store='Store 2'
LEFT JOIN cte_sell as Store_3 ON a.item_id=store_3.item_id and a.date=store_3.date and store='Store 3'

答案 1 :(得分:0)

我认为问题在于SQL Server在查询中多次出现时似乎没有优化它们。换句话说,如果您查看执行计划,则视图将被执行三次 - 对于每个提及商店。

您可以将每个商店放在不同的行上吗?如果是这样,试试这个:

WITH cte_sell AS (
    SELECT * 
    FROM view_turnover 
    WHERE date BETWEEN '130413' and '130418'
   )
SELECT a.item_id, a.date, store, turnover, quantity
FROM (SELECT DISTINCT item_id,date FROM cte_sell) as a left join
     cte_sell cs
     on a.item_id=cs.item_id and a.date=cs.date and cs.store in ('Store 1', 'Store 2', 'Store 3')

如果您需要一行包含多个商店,那么条件聚合或pivot将解决问题。

如果要在一行中查看所有值,请在上述查询中使用条件聚合:

WITH cte_sell AS (
    SELECT * 
    FROM view_turnover 
    WHERE date BETWEEN '130413' and '130418'
   )
SELECT a.item_id, a.date,
       max(case when store = 'Store 1' then turnover end),
       max(case when store = 'Store 1' then quantity end),
       max(case when store = 'Store 2' then turnover end),
       max(case when store = 'Store 2' then quantity end),
       max(case when store = 'Store 3' then turnover end),
       max(case when store = 'Store 3' then quantity end)
FROM (SELECT DISTINCT item_id,date FROM cte_sell) as a left join
     cte_sell cs
     on a.item_id=cs.item_id and a.date=cs.date and cs.store in ('Store 1', 'Store 2', 'Store 3')
group by a.item_id, a.date