当它来到数据库时,我几乎是个白痴,我可以编写查询来做我想要的而没有太多问题,但是当我遇到性能问题时我真的不知道该怎么做,所以任何帮助我将非常感激。
我有三张桌子:
比尔
BillDetail
BillDetailType
每张账单都有多个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 小时运行,我真的不明白为什么。
如果删除任何一个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秒。
我不明白为什么其中任何一个连接本身都在这么短的时间内运行,但是当我一起进行连接时需要几个小时。也许这是非常明显的,但因为我真的不明白如何评估查询我错过了它。我查看了执行计划,但我无法收集任何有用的东西,而且我有点死路一条。我已经尝试了各种方法来切换事物,将其中一个连接移动到子查询以及我认为可能有帮助的其他事情,但我所做的一切都没有改变性能。
感谢您的帮助。
答案 0 :(得分: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年中学到的各种技巧。
答案 1 :(得分:0)
如果没有看到确切的执行计划,很难知道,但是您很有可能需要在视图上创建一些索引。查询优化器不一定会使用基础表上的索引,您可能需要专门在视图本身上创建索引。
执行计划的屏幕截图可以让分析更容易。
来自MSDN article:It 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.
(强调我的)。