我试图在表格数据整理中做很多事情,其中单个记录需要根据同一个表整理数据,但是按日期记录先前的记录。
目前我有6个外部申请,大约需要3分钟才能运行1个日期。我可能需要50多个计算字段和多个日期,所以这开始变得不可行了。
有没有更好的方法来提高查询速度?
DECLARE @Date datetime;
SET @Date = '2018-01-01';
SELECT * --Not real Select, set as * to simplify
-- Following subquery normally contains methods to clean data
FROM (SELECT t1.* FROM (SELECT cleanFields1.* FROM Control AS cleanFields1
WHERE cleanFields1.[QDate] = @Date) AS t1) t1
-- Calculated Data
OUTER APPLY (
SELECT COUNT(*) AS ProductCountMonth
FROM Control t6
WHERE t6.[ProductName] = t1.[ProductName]
AND t6.[QDate] < t1.[QDate]
AND MONTH(t6.[QDate]) = MONTH(t1.[QDate])
) t6
OUTER APPLY (
SELECT COUNT(*) AS ProductMatchMonth
FROM Control t7
WHERE t7.[ProductName] = t1.[ProductName]
AND t7.[QDate] < t1.[QDate]
AND t7.[Issue] = '1'
AND MONTH(t7.[QDate]) = MONTH(t1.[QDate])
) t7
OUTER APPLY (
SELECT COUNT(*) AS ProductCountArea
FROM Control t8
WHERE t8.[ProductName] = t1.[ProductName]
AND t8.[QDate] < t1.[QDate]
AND t8.[AreaName] = t1.[AreaName]
) t8
OUTER APPLY (
SELECT COUNT(*) AS ProductMatchArea
FROM Control t9
WHERE t9.[ProductName] = t1.[ProductName]
AND t9.[QDate] < t1.[QDate]
AND t9.[Issue] = '1'
AND t9.[AreaName] = t1.[AreaName]
) t9
OUTER APPLY (
SELECT COUNT(*) AS ProductCountPType
FROM Control t10
WHERE t10.[ProductName] = t1.[ProductName]
AND t10.[QDate] < t1.[QDate]
AND t10.[PType] = t1.[PType]
) t10
OUTER APPLY (
SELECT COUNT(*) AS ProductMatchPType
FROM Control t11
WHERE t11.[ProductName] = t1.[ProductName]
AND t11.[QDate] < t1.[QDate]
AND t11.[Issue] = '1'
AND t11.[PType] = t1.[PType]
) t11
编辑:
SQLFiddle:http://sqlfiddle.com/#!18/9541d/1
答案 0 :(得分:3)
您可以消除所有这些将极大地帮助提高性能的交叉应用。当Issue是int时,你应该避免像'1'这样的东西。你应该使用1。
在这种情况下,我使用cte来展示如何隔离要返回的行。从那只是一些条件聚合。
DECLARE @Date datetime = '2018-01-01';
with CurrentRows as
(
select *
from Control c
where c.QDate = @Date
)
select cr.*
, ProductCountMonth = sum(case when MONTH(c.QDate) = MONTH(cr.QDate) then 1 else 0 end)
, ProductMatchMonth = sum(case when MONTH(c.QDate) = MONTH(cr.QDate) AND c.Issue = 1 then 1 else 0 end)
, ProductCountArea = sum(case when c.AreaName = cr.AreaName then 1 else 0 end)
, ProductMatchArea = sum(case when c.Issue = 1 and c.AreaName = cr.AreaName then 1 else 0 end)
, ProductCountPType = sum(case when c.PType = cr.PType then 1 else 0 end)
, ProductMatchPType = sum(case when c.PType = cr.PType and c.Issue = 1 then 1 else 0 end)
from CurrentRows cr
join Control c on c.QDate < cr.QDate and c.ProductName = cr.ProductName
group by cr.QDate
, cr.ProductName
, cr.AreaName
, cr.PType
, cr.Issue
order by cr.AreaName
答案 1 :(得分:1)
在您的示例中,您可以将6个外部应用组合成3并将执行时间缩短一些。
SELECT * --Not real Select, set as * to simplify
FROM (SELECT t1.* FROM (SELECT cleanFields1.* FROM Control AS cleanFields1
WHERE cleanFields1.[QDate] = '2018-01-01') AS t1) t1
OUTER APPLY (
SELECT COUNT(*) ProductCountMonth,
COUNT(CASE WHEN t2.Issue = 1 THEN 1 END) ProductMatchMonth
FROM Control t2
WHERE t2.ProductName = t1.ProductName
AND t2.[QDate] < t1.[QDate]
AND MONTH(t2.[QDate]) = MONTH(t1.[QDate])
) t2
OUTER APPLY (
SELECT COUNT(*) ProductCountArea,
COUNT(CASE WHEN t3.Issue = 1 THEN 1 END) ProductMatchArea
FROM Control t3
WHERE t3.ProductName = t1.ProductName
AND t3.[QDate] < t1.[QDate]
AND t3.AreaName = t1.AreaName
) t3
OUTER APPLY (
SELECT COUNT(*) ProductCountPType,
COUNT(CASE WHEN t4.Issue = 1 THEN 1 END) ProductMatchPType
FROM Control t4
WHERE t4.ProductName = t1.ProductName
AND t4.[QDate] < t1.[QDate]
AND t4.PType = t1.PType
) t4
这会在匹配计数中使用案例表达式来确定Issue = 1。
答案 2 :(得分:1)
我建议您将outer apply's
更改为窗口功能。必须更快。但您的SQL版本必须至少为2012
DECLARE @Date datetime;
SET @Date = '2018-01-01';
select
*
from (
SELECT
cleanFields1.*
, row_number() over (partition by ProductName, month(QDate) order by QDate) - 1 AS ProductCountMonth
, sum(iif(Issue = 1, 1, 0)) over (partition by ProductName, month(QDate) order by QDate) AS ProductMatchMonth
, row_number() over (partition by ProductName, AreaName order by QDate) - 1 AS ProductCountArea
, sum(iif(Issue = 1, 1, 0)) over (partition by ProductName, AreaName order by QDate) AS ProductMatchArea
, row_number() over (partition by ProductName, PType order by QDate) - 1 AS ProductCountPType
, sum(iif(Issue = 1, 1, 0)) over (partition by ProductName, PType order by QDate) AS ProductMatchPType
FROM
Control AS cleanFields1
) t
where
QDate = @Date