【问题标题】:SQL Server multiple INNER JOINs very slowSQL Server 多个 INNER JOIN 非常慢
【发布时间】:2012-06-30 23:46:17
【问题描述】:

在数据库方面我几乎是个白痴,我可以编写查询来做我想做的事而不会出现太多问题,但是当我遇到性能问题时,我真的不知道该怎么做,所以请帮忙将不胜感激。

我有三张桌子:

比尔

  • Bill_Id - BIGINT - 主键
  • 账单日期 - 日期

账单详情

  • BillDetail_Id - BIGINT - 主键
  • Bill_Id - BIGINT - Bill 的外键,索引
  • BillDetailType_Id - INT - BillDetailType 的外键,已编入索引
  • 收费 - 钱

BillDetailType

  • BillDetailType_Id - INT - 主键
  • 类型名称 - NVARCHAR(20)

每个账单都有多个 BillDetails,它们基本上是账单上的各个项目。每个 BillDetail 都有一个 BillDetailType,它是什么类型的账单项目(例如电费、互联网、税收)。

我还创建了这样的视图:

CREATE VIEW BillSubtotal
AS
SELECT b.*,
        (SELECT SUM(bd.Charge) FROM BillDetail AS bd INNER JOIN BillDetailType AS bdt ON bd.BillDetailType_Id = bdt.BillDetailType_Id
            WHERE (bdt.TypeName = 'Tax') AND (bd.Bill_Id = b.Bill_id)) AS Tax,
        (SELECT SUM(bd.Charge) FROM BillDetail AS bd INNER JOIN BillDetailType AS bdt ON bd.BillDetailType_Id = bdt.BillDetailType_Id
            WHERE (bdt.TypeName <> 'Tax') AND (bd.Bill_Id = b.Bill_id)) AS NonTaxTotal
        FROM Bill AS b

使用当前的开发数据库运行该视图大约需要 14 秒,其中大约有 60000 个账单和 700000 个账单详细信息。有 26 种不同的 BillDetailType。一旦我得到这个工作,我想添加更多的小计,但现在这就是我所拥有的。

现在我正在尝试像这样进行连接:

SELECT bs.BillDate, bs.Tax, bs.NonTaxTotal, bd.Charge, bdt.TypeName FROM
BillDetail bd
INNER JOIN BillSubtotal bs ON bs.Bill_Id = bd.Bill_Id
INNER JOIN BillDetailType bdt ON bdt.BillDetailType_Id = bd.BillDetailType_Id

我想计算特定 BillDetail 占税前账单的百分比以及其他一些东西,所以我最终会得到类似 bd.Charge/bs.NonTaxTotal*100 的东西,但目前这个查询需要 14 小时 运行,我真的不明白为什么。

如果我删除任何一个 INNER JOIN,查询会显着加快:

SELECT bs.BillDate, bs.Tax, bs.NonTaxTotal, bd.Charge FROM
BillDetail bd
INNER JOIN BillSubtotal bs ON bs.Bill_Id = bd.Bill_Id

运行大约需要 1.5 分钟。

SELECT bd.Charge, bdt.TypeName FROM
BillDetail bd
INNER JOIN BillDetailType bdt ON bdt.BillDetailType_Id = bd.BillDetailType_Id

大约需要 12 秒。

我不明白为什么任何一个连接都可以在这么短的时间内运行,但是当我一起进行连接时需要几个小时。也许这是非常明显的事情,但是因为我并不真正了解如何评估查询,所以我错过了它。我查看了执行计划,但我无法从中收集到任何有用的信息,而且我有点走投无路。我尝试了各种切换方式,将其中一个连接移动到子查询以及其他我认为可能会有所帮助的方法,但我所做的一切都没有改变性能。

感谢您的帮助。

【问题讨论】:

    标签: sql-server query-optimization


    【解决方案1】:

    我建议根本不要使用视图。几年前我做了很多这样的事情,但它们在很长一段时间内变得难以管理。如果向其中一个表添加列,则应更新视图。只是变得太费力了。话虽如此,您可以向视图添加索引。

    我还建议使用 Group By 策略。根据我的经验,这可能会快很多。我在几个案例中使用过它,发现速度有了显着的提高。像这样的:

     SELECT Bill_Id, 
         SUM(BillDetail.Charge), 
         CASE
             WHEN BillDetailType.TypeName = 'Tax'
                 THEN 'Tax'
                 ELSE 'Not Tax'
         END AS TypeName            
     FROM BillDetail
         INNER JOIN BillDetailType 
             ON BillDetail.BillDetailType_Id = BillDetailType.BillDetailType_Id
     GROUP BY Bill_Id, TypeName
    

    您可以只使用此查询并加入该查询,而不是创建视图。这将利用表本身的索引。

    最后,您可能想尝试通过 Sql Server Profiler 工具运行最终得到的任何查询。

    我有一篇关于 SQL Query Optimization 的博文,其中讲述了我在过去 7 年中学到的各种技术。

    【讨论】:

      【解决方案2】:

      没有看到确切的执行计划很难知道,但很有可能您需要在视图上创建一些索引。查询优化器不一定会使用基础表上的索引,您可能需要专门在视图本身上创建索引。

      执行计划的屏幕截图会更容易分析。

      来自MSDN articleIt is possible to create a unique clustered index on a view, as well as nonclustered indexes, to improve data access performance on the most complex queries by precomputing and materializing the view. **This is often particularly effective for aggregate views** in decision support or data warehouse environments.(重点是我的)。

      【讨论】:

        猜你喜欢
        • 2015-07-12
        • 2015-10-31
        • 2018-03-09
        • 2011-07-29
        • 2018-06-26
        • 2016-09-22
        • 2011-03-03
        • 2014-01-22
        相关资源
        最近更新 更多