误用的数据库视图 (SQL Server) - 如何优化
Posted
技术标签:
【中文标题】误用的数据库视图 (SQL Server) - 如何优化【英文标题】:Misused database view (SQL Server) - how to optimize 【发布时间】:2018-01-11 00:33:32 【问题描述】:我需要一些关于如何优化 SQL 查询的建议,因为我不是 SQL 专家。
我的一个客户有一些在 SQL Server 上运行的 SQL 代码,他们希望它运行得更快。以前跑得快,现在不行了。
查询每天使用相同的大视图 6 次来提取数据,这是导致它非常慢的主要原因,运行时间超过 25 分钟。
主要问题似乎是视图被调用了很多次,运行之间的差异很小。
是否可以重写查询,使其只调用一次视图,然后从中提取一周的数据,是否可以在不使用临时表的情况下完成?
-- Imput: @justWeekEnding - the date for the end of week report
-- Input: @customerid - the unique customer ID for whom the report is generated
-- Expected output: Sales report, showing profit margin for the selected customer per shop per day-of-week
--
-- dbo.charting_salesdata: View producing a sales report across all stores per date per customer
-- dbo.stores: Table containing store info
-- dbo.receipts: Table containing all receipts
-- dbo.storecategories: Table containing all store categories
DECLARE @justWeekEnding AS date;
SET @justWeekEnding = CONVERT(date, @weekEnding, 101);
SELECT
Query.StoreName AS [Store Name], Query.POS as [POS Name],
Query.saturday, Query.sunday, Query.monday, Query.tuesday,
Query.wednesday, Query.thursday, Query.friday
FROM
(SELECT
dbo.stores.NAME AS [StoreName],
receipts.POS AS [POS],
(SELECT COUNT(percentage)
FROM dbo.charting_salesdata WITH (nolock)
WHERE dbo.charting_salesdata.receiptid = dbo.receipts.receiptid
AND dateofsale = Dateadd(d, -6, @justWeekEnding)
GROUP BY receiptid, dateofsale) AS saturday,
(SELECT COUNT(percentage)
FROM dbo.charting_salesdata WITH (nolock)
WHERE dbo.charting_salesdata.receiptid = dbo.receipts.receiptid
AND dateofsale = Dateadd(d, -5, @justWeekEnding)
GROUP BY receiptid, dateofsale) AS sunday,
(SELECT COUNT(percentage)
FROM dbo.charting_salesdata WITH (nolock)
WHERE dbo.charting_salesdata.receiptid = dbo.receipts.receiptid
AND dateofsale = Dateadd(d, -4, @justWeekEnding)
GROUP BY receiptid, dateofsale) AS monday,
(SELECT COUNT(percentage)
FROM dbo.charting_salesdata WITH (nolock)
WHERE dbo.charting_salesdata.receiptid = dbo.receipts.receiptid
AND dateofsale = Dateadd(d, -3, @justWeekEnding)
GROUP BY receiptid, dateofsale) AS tuesday,
(SELECT COUNT(percentage)
FROM dbo.charting_salesdata WITH (nolock)
WHERE dbo.charting_salesdata.receiptid = dbo.receipts.receiptid
AND dateofsale = Dateadd(d, -2, @justWeekEnding)
GROUP BY receiptid, dateofsale) AS wednesday,
(SELECT COUNT(percentage)
FROM dbo.charting_salesdata WITH (nolock)
WHERE dbo.charting_salesdata.receiptid = dbo.receipts.receiptid
AND dateofsale = Dateadd(d, -1, @justWeekEnding)
GROUP BY receiptid, dateofsale) AS thursday,
(SELECT COUNT(percentage)
FROM dbo.charting_salesdata WITH (nolock)
WHERE dbo.charting_salesdata.receiptid = dbo.receipts.receiptid
AND dateofsale = @justWeekEnding
GROUP BY receiptid, dateofsale) AS friday,
(SELECT COUNT(percentage)
FROM dbo.charting_salesdata WITH (nolock)
WHERE dbo.charting_salesdata.receiptid = dbo.receipts.receiptid
AND dateofsale BETWEEN Dateadd(d, -6, @justWeekEnding) AND @justWeekEnding) AS TOTAL
FROM
receipts WITH (nolock)
INNER JOIN
dbo.stores WITH (nolock) ON dbo.receipts.storeid = dbo.stores.storeid
INNER JOIN
dbo.storecategories WITH (nolock) ON dbo.stores.storecategoryid = dbo.storecategories.storecategoryid
WHERE
1=1
AND customerid = @customerid
AND dbo.receipts.isdeleted = 0) AS Query
WHERE
Query.TOTAL > 0
ORDER BY
Query.StoreName, Query.TargetName
【问题讨论】:
设置Bad Habits to kick - putting NOLOCK everywhere - 不推荐在任何地方使用它 - 恰恰相反! 感谢您的建议。我继承的 SQL 到处都有它们……我将开始摆脱它们。到处使用它们的原因是什么? 【参考方案1】:是的,这是可能的。
按 dateofsale、receiptid、dateofsale 对所有内容进行分组,并应用日期过滤器,然后 PIVOT 结果(将行(一周中的 7 天)旋转到列)
https://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx
【讨论】:
这听起来是一个很好的解决方案,正是我所需要的。非常感谢。【参考方案2】:使用@justweekEnding 日期过滤器为按日期分组的列 dateofsale、receiped、dateofsale 的视图创建 CTE(通用类型表达式)。
然后您可以创建一个查询,该查询将其他表与 CTE 连接起来并执行 Pivot 以获取所有列,例如周六、周日、周一
【讨论】:
感谢您的意见。我以前没有使用过 CTE,我会研究一下。以上是关于误用的数据库视图 (SQL Server) - 如何优化的主要内容,如果未能解决你的问题,请参考以下文章
sql server 2008怎么修改视图中的字段属性!!例如修改字段名和字段类型!