2012-06-30 110 views
1

当我来到数据库时,我几乎是一个白痴,我可以编写查询来做我想要的而没有太多问题,但是当我遇到性能问题时,我真的不知道该怎么做,所以任何帮助将受到感谢。SQL Server多个INNER JOINs非常慢

我有三个表:

比尔

  • Bill_Id - BIGINT - 主键
  • BillDate - DATE

BillDetail

  • BillDetail_Id - BIGINT - 主键
  • Bill_Id - BIGINT - 比尔外键,索引
  • BillDetailType_Id - INT - 为BillDetailType外键,索引
  • 费 - MONEY

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个BillDetails。有26种不同的BillDetailTypes。一旦我得到这个工作,我想添加更多小计,但现在就是我所拥有的。

现在,我试图做一个加入这样的:

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 小时运行,我真的不明白为什么。

如果我取下内的任何连接,查询,大大加快:

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秒。

我不明白为什么要在这么短的时间内运行连接,但是当我连接在一起需要花费数小时。也许这是非常明显的,但因为我不真正了解如何评估查询我错过了它。我看着执行计划,但我无法从它那里收集任何有用的信息,而我却处于死胡同。我尝试了各种切换方法,将其中一个连接移动到子查询和其他我认为可能有用的事情上,但我所做的任何事情都改变了性能。

感谢您的任何帮助。

+0

'TypeName'是否是唯一的? – Neil

+1

发布您的查询计划 – praveen

回答

0

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

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

来自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.(强调我的)。

3

我会建议不要使用视图。我在几年前做了一些这样的事情,但是很长一段时间他们很难管理。如果您向其中一个表格添加列,则应更新视图。它变得太辛苦了。话虽如此,你可以添加索引到视图。我也建议使用组按策略。根据我的经验,这可以快得多。我已经在几种情况下使用了它,并发现速度显着提高。类似这样的:

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年中学到的各种技术。