我正在为下面的报告编写一个复杂的视图:
SELECT TOP (100) PERCENT dbo.tbl_SFCWRK_SQL_NF.ID, dbo.tbl_SFCWRK_SQL_NF.STD_LBR_HRS, dbo.tbl_SFCWRK_SQL_NF.CUSTNAME,
dbo.tbl_SFCWRK_SQL_NF.JOBNBR, CASE WHEN dbo.tbl_SFCWRK_SQL_NF.COMPQTY IS NULL THEN 0 ELSE CONVERT(decimal(10, 5),
dbo.tbl_SFCWRK_SQL_NF.COMPQTY) END AS COMPQTY, CASE WHEN dbo.tbl_SFCWRK_SQL_NF.ORDQTY IS NULL THEN 0 ELSE CONVERT(decimal(10, 5),
dbo.tbl_SFCWRK_SQL_NF.ORDQTY) END AS ORDQTY, dbo.tbl_SFCWRK_SQL_NF.PLAN_CD, dbo.tbl_SFCWRK_SQL_NF.PLANQTY,
dbo.tbl_SFCWRK_SQL_NF.ITEMNBR, dbo.tbl_ITEMMAST_NF.ITEM_NBR, dbo.tbl_SFCWRK_SQL_NF.WODUEDT, tbl_WORK_CENTR_NF.WRK_CENTER_DESC,
tbl_WORK_CENTR_NF.LABOR_CAPACITY, dbo.tbl_SFCWRK_SQL_NF.STD_SETUP_HRS, dbo.tbl_WIPOPER_NF.STD_LBR_HOURS,
dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE, dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR, dbo.tbl_WIPOPER_NF.OPER_STATUS,
dbo.tbl_WIPOPER_NF.OPERATION_NBR, tbl_WORK_CENTR_NF.WAREHOUSE,
CASE WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20005' THEN 1 WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20010' THEN 2 WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR
= '20020' THEN 3 WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20030' THEN 4 WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20040' THEN 5 WHEN
dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20050' THEN 6 WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20110' THEN 7 ELSE dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR
END AS WCOrder, DATEADD(dd, 7 - DATEPART(dw, dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE), dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE) AS WeekEnd,
DATEPART(wk, dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE) AS WkNum,
CASE WHEN dbo.tbl_SFCWRK_SQL_NF.COMPQTY <> 0 THEN ((dbo.tbl_SFCWRK_SQL_NF.STD_LBR_HRS / dbo.tbl_SFCWRK_SQL_NF.ORDQTY)
* (dbo.tbl_SFCWRK_SQL_NF.ORDQTY - dbo.tbl_SFCWRK_SQL_NF.COMPQTY))
* 2 ELSE ((dbo.tbl_SFCWRK_SQL_NF.STD_LBR_HRS / dbo.tbl_SFCWRK_SQL_NF.ORDQTY) * (dbo.tbl_SFCWRK_SQL_NF.ORDQTY)) * 2 END AS RmnLabor,
CASE WHEN dbo.tbl_SFCWRK_SQL_NF.COMPQTY <> 0 THEN ((dbo.tbl_SFCWRK_SQL_NF.STD_SETUP_HRS / tbl_SFCWRK_SQL_NF.ORDQTY)
* (dbo.tbl_SFCWRK_SQL_NF.ORDQTY - dbo.tbl_SFCWRK_SQL_NF.COMPQTY))
/ 100 ELSE ((dbo.tbl_SFCWRK_SQL_NF.STD_SETUP_HRS / dbo.tbl_SFCWRK_SQL_NF.ORDQTY) * (dbo.tbl_SFCWRK_SQL_NF.ORDQTY))
/ 100 END AS RmnSetup
FROM dbo.tbl_ITEMMAST_NF INNER JOIN
dbo.tbl_SFCWRK_SQL_NF ON dbo.tbl_ITEMMAST_NF.CPN = dbo.tbl_SFCWRK_SQL_NF.CPN_NO INNER JOIN
dbo.tbl_WORK_CENTR_NF AS tbl_WORK_CENTR_NF ON dbo.tbl_SFCWRK_SQL_NF.WC_NBR = tbl_WORK_CENTR_NF.ID INNER JOIN
dbo.tbl_WIPOPER_NF ON dbo.tbl_SFCWRK_SQL_NF.ID = dbo.tbl_WIPOPER_NF.ID
WHERE (dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE <= DATEADD(m, 2, GETDATE())) AND (dbo.tbl_WIPOPER_NF.OPER_STATUS <> 'C' OR
dbo.tbl_WIPOPER_NF.OPER_STATUS IS NULL OR
dbo.tbl_WIPOPER_NF.OPER_STATUS = '') AND (tbl_WORK_CENTR_NF.WAREHOUSE = '02') AND (dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR IN ('20005', '20010',
'20020', '20030', '20040', '20060', '20110')) AND (NOT (dbo.tbl_ITEMMAST_NF.ITEM_NBR LIKE 'A%')) AND (CASE WHEN tbl_SFCWRK_SQL_NF.ORDQTY IS NULL
THEN 0 ELSE CONVERT(decimal(10, 5), tbl_SFCWRK_SQL_NF.ORDQTY) END <> 0) AND (CASE WHEN tbl_SFCWRK_SQL_NF.ORDQTY IS NULL
THEN 0 ELSE CONVERT(decimal(10, 5), tbl_SFCWRK_SQL_NF.ORDQTY) END <> 0)
ORDER BY dbo.tbl_SFCWRK_SQL_NF.WODUEDT DESC
我想让这次运行更有效率。 我也很好奇,如果我正在做的是写View的正确方法,我是否应该重构它???
赖安
答案 0 :(得分:2)
这对我来说没什么意义
where
(CASE
WHEN tbl_SFCWRK_SQL_NF.ORDQTY IS NULL THEN 0
ELSE CONVERT(decimal(10, 5), tbl_SFCWRK_SQL_NF.ORDQTY) END
<> 0)
如果为null则返回false 但任何与null的比较都会返回false。
必须是转换为十进制才能成功的数字类型 使用任何数字类型&lt;&gt; 0是一样的。
非常确定可以缩减为
where tbl_SFCWRK_SQL_NF.ORDQTY <> 0
使用您的语法可以终止在该列上使用索引
另外&lt;&gt; 'c'或=''是多余的
看到tbl_SFCWRK_SQL_NF.ORDQTY是varchar的评论
那只是搞砸了。
如果任何varchar值不是十进制,则转换将失败
我只是假设它必须是某种类型的数字。
答案 1 :(得分:1)
首先,views
上的最佳做法不包含ORDER BY
。所以摆脱TOP (100) PERCENT
和ORDER BY dbo.tbl_SFCWRK_SQL_NF.WODUEDT DESC
语句。接下来格式化您的查询,以便它易于阅读。我在下面做了这个,但如果你有不同的格式,你更喜欢使用它。这一切都是为了让你和你的队友/最终替换它可读。
格式化后,我可以告诉您应该检查以下索引。
这些是基于您在JOIN
和WHERE
子句中使用的列的起始位置。它们可能不是最优的,但可能总比没有好。您还可以检查执行计划,看看优化器是否提出了建议。如果它确实检查了您现有的索引并查看它是否适合它们,如果确实如此,则添加它。如果没有,则可以修改您现有的一个索引以涵盖它所要求的内容。
例如,假设您创建了上面的索引,但优化程序需要以下索引。
tbl_WIPOPER_NF(ID, SCHED_COMP_DATE, OPER_STATUS) INCLUDE WORK_CENTER_NBR
不要只添加新索引。修改旧的列以包含INCLUDE
ed列。或者优化器可能希望您更改索引中列的顺序。如果这是你使用该索引的唯一地方(因为我建议你添加它),然后修改它。不要添加新的。与您已有的索引相比,我的建议也是如此。
就查询本身而言。看起来很好。还有一些其他方法可以处理事情,例如使用ISNULL
而不是CASE
子句中的WHERE
语句。但你拥有它的方式应该工作得很好。
SELECT --TOP (100) PERCENT
dbo.tbl_SFCWRK_SQL_NF.ID, dbo.tbl_SFCWRK_SQL_NF.STD_LBR_HRS,
dbo.tbl_SFCWRK_SQL_NF.CUSTNAME, dbo.tbl_SFCWRK_SQL_NF.JOBNBR,
CASE WHEN dbo.tbl_SFCWRK_SQL_NF.COMPQTY IS NULL THEN 0
ELSE CONVERT(decimal(10, 5), dbo.tbl_SFCWRK_SQL_NF.COMPQTY) END AS COMPQTY,
CASE WHEN dbo.tbl_SFCWRK_SQL_NF.ORDQTY IS NULL THEN 0
ELSE CONVERT(decimal(10, 5), dbo.tbl_SFCWRK_SQL_NF.ORDQTY) END AS ORDQTY,
dbo.tbl_SFCWRK_SQL_NF.PLAN_CD, dbo.tbl_SFCWRK_SQL_NF.PLANQTY,
dbo.tbl_SFCWRK_SQL_NF.ITEMNBR, dbo.tbl_ITEMMAST_NF.ITEM_NBR,
dbo.tbl_SFCWRK_SQL_NF.WODUEDT, tbl_WORK_CENTR_NF.WRK_CENTER_DESC,
tbl_WORK_CENTR_NF.LABOR_CAPACITY, dbo.tbl_SFCWRK_SQL_NF.STD_SETUP_HRS,
dbo.tbl_WIPOPER_NF.STD_LBR_HOURS, dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE,
dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR, dbo.tbl_WIPOPER_NF.OPER_STATUS,
dbo.tbl_WIPOPER_NF.OPERATION_NBR, tbl_WORK_CENTR_NF.WAREHOUSE,
CASE WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20005' THEN 1
WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20010' THEN 2
WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20020' THEN 3
WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20030' THEN 4
WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20040' THEN 5
WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20050' THEN 6
WHEN dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20110' THEN 7
ELSE dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR END AS WCOrder,
DATEADD(dd, 7 - DATEPART(dw, dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE),
dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE) AS WeekEnd, DATEPART(wk, dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE) AS WkNum,
CASE WHEN dbo.tbl_SFCWRK_SQL_NF.COMPQTY <> 0
THEN ((dbo.tbl_SFCWRK_SQL_NF.STD_LBR_HRS / dbo.tbl_SFCWRK_SQL_NF.ORDQTY) *
(dbo.tbl_SFCWRK_SQL_NF.ORDQTY - dbo.tbl_SFCWRK_SQL_NF.COMPQTY)) * 2
ELSE ((dbo.tbl_SFCWRK_SQL_NF.STD_LBR_HRS / dbo.tbl_SFCWRK_SQL_NF.ORDQTY) *
(dbo.tbl_SFCWRK_SQL_NF.ORDQTY)) * 2 END AS RmnLabor,
CASE WHEN dbo.tbl_SFCWRK_SQL_NF.COMPQTY <> 0
THEN ((dbo.tbl_SFCWRK_SQL_NF.STD_SETUP_HRS / tbl_SFCWRK_SQL_NF.ORDQTY) *
(dbo.tbl_SFCWRK_SQL_NF.ORDQTY - dbo.tbl_SFCWRK_SQL_NF.COMPQTY)) / 100
ELSE ((dbo.tbl_SFCWRK_SQL_NF.STD_SETUP_HRS / dbo.tbl_SFCWRK_SQL_NF.ORDQTY) *
(dbo.tbl_SFCWRK_SQL_NF.ORDQTY)) / 100 END AS RmnSetup
FROM dbo.tbl_ITEMMAST_NF
INNER JOIN dbo.tbl_SFCWRK_SQL_NF
ON dbo.tbl_ITEMMAST_NF.CPN = dbo.tbl_SFCWRK_SQL_NF.CPN_NO
INNER JOIN dbo.tbl_WORK_CENTR_NF AS tbl_WORK_CENTR_NF
ON dbo.tbl_SFCWRK_SQL_NF.WC_NBR = tbl_WORK_CENTR_NF.ID
INNER JOIN dbo.tbl_WIPOPER_NF
ON dbo.tbl_SFCWRK_SQL_NF.ID = dbo.tbl_WIPOPER_NF.ID
WHERE (dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE <= DATEADD(m, 2, GETDATE()))
AND (dbo.tbl_WIPOPER_NF.OPER_STATUS <> 'C' OR
dbo.tbl_WIPOPER_NF.OPER_STATUS IS NULL OR
dbo.tbl_WIPOPER_NF.OPER_STATUS = '')
AND (tbl_WORK_CENTR_NF.WAREHOUSE = '02')
AND (dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR IN ('20005', '20010', '20020', '20030',
'20040', '20060', '20110'))
AND (NOT (dbo.tbl_ITEMMAST_NF.ITEM_NBR LIKE 'A%'))
AND (CASE WHEN tbl_SFCWRK_SQL_NF.ORDQTY IS NULL THEN 0
ELSE CONVERT(decimal(10, 5), tbl_SFCWRK_SQL_NF.ORDQTY) END <> 0)
AND (CASE WHEN tbl_SFCWRK_SQL_NF.ORDQTY IS NULL THEN 0
ELSE CONVERT(decimal(10, 5), tbl_SFCWRK_SQL_NF.ORDQTY) END <> 0)
--ORDER BY dbo.tbl_SFCWRK_SQL_NF.WODUEDT DESC
答案 2 :(得分:1)
我对查询做了一些小的更新和格式化,可能会有所帮助;使用IS NULL
代替COALESCE
语句检查CASE
并清空字符串。请参阅下文了解详情。我不确定这些是否会影响性能,但你可以尝试一下。
请注意,您的上一个条件已列出两次。我不确定这是否是故意的,或者它是否会对性能产生影响。让我知道。如果没有,那么我将删除这个答案。
SELECT
dbo.tbl_SFCWRK_SQL_NF.ID,
dbo.tbl_SFCWRK_SQL_NF.STD_LBR_HRS,
dbo.tbl_SFCWRK_SQL_NF.CUSTNAME,
dbo.tbl_SFCWRK_SQL_NF.JOBNBR,
--CASE WHEN dbo.tbl_SFCWRK_SQL_NF.COMPQTY IS NULL THEN 0 ELSE CONVERT(decimal(10, 5), dbo.tbl_SFCWRK_SQL_NF.COMPQTY) END AS COMPQTY,
COALESCE(CONVERT(decimal(10, 5), dbo.tbl_SFCWRK_SQL_NF.COMPQTY), 0) AS COMPQTY
--CASE WHEN dbo.tbl_SFCWRK_SQL_NF.ORDQTY IS NULL THEN 0 ELSE CONVERT(decimal(10, 5), dbo.tbl_SFCWRK_SQL_NF.ORDQTY) END AS ORDQTY,
COALESCE(CONVERT(decimal(10, 5), dbo.tbl_SFCWRK_SQL_NF.ORDQTY), 0) AS ORDQTY
dbo.tbl_SFCWRK_SQL_NF.PLAN_CD,
dbo.tbl_SFCWRK_SQL_NF.PLANQTY,
dbo.tbl_SFCWRK_SQL_NF.ITEMNBR,
dbo.tbl_ITEMMAST_NF.ITEM_NBR,
dbo.tbl_SFCWRK_SQL_NF.WODUEDT,
tbl_WORK_CENTR_NF.WRK_CENTER_DESC,
tbl_WORK_CENTR_NF.LABOR_CAPACITY,
dbo.tbl_SFCWRK_SQL_NF.STD_SETUP_HRS,
dbo.tbl_WIPOPER_NF.STD_LBR_HOURS,
dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE,
dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR,
dbo.tbl_WIPOPER_NF.OPER_STATUS,
dbo.tbl_WIPOPER_NF.OPERATION_NBR,
tbl_WORK_CENTR_NF.WAREHOUSE,
CASE
WHEN
dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20005'
THEN
1
WHEN
dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20010'
THEN
2
WHEN
dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20020'
THEN
3
WHEN
dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20030'
THEN
4
WHEN
dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20040'
THEN
5
WHEN
dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20050'
THEN
6
WHEN
dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR = '20110'
THEN
7
ELSE
dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR
END
AS WCOrder,
DATEADD(dd, 7 - DATEPART(dw, dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE), dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE) AS WeekEnd,
DATEPART(wk, dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE) AS WkNum,
CASE
WHEN
dbo.tbl_SFCWRK_SQL_NF.COMPQTY <> 0
THEN
((dbo.tbl_SFCWRK_SQL_NF.STD_LBR_HRS / dbo.tbl_SFCWRK_SQL_NF.ORDQTY) * (dbo.tbl_SFCWRK_SQL_NF.ORDQTY - dbo.tbl_SFCWRK_SQL_NF.COMPQTY)) * 2
ELSE
((dbo.tbl_SFCWRK_SQL_NF.STD_LBR_HRS / dbo.tbl_SFCWRK_SQL_NF.ORDQTY) * (dbo.tbl_SFCWRK_SQL_NF.ORDQTY)) * 2
END AS RmnLabor,
CASE
WHEN
dbo.tbl_SFCWRK_SQL_NF.COMPQTY <> 0
THEN
((dbo.tbl_SFCWRK_SQL_NF.STD_SETUP_HRS / tbl_SFCWRK_SQL_NF.ORDQTY) * (dbo.tbl_SFCWRK_SQL_NF.ORDQTY - dbo.tbl_SFCWRK_SQL_NF.COMPQTY)) / 100
ELSE
((dbo.tbl_SFCWRK_SQL_NF.STD_SETUP_HRS / dbo.tbl_SFCWRK_SQL_NF.ORDQTY) * (dbo.tbl_SFCWRK_SQL_NF.ORDQTY)) / 100
END AS RmnSetup
FROM
dbo.tbl_ITEMMAST_NF INNER JOIN dbo.tbl_SFCWRK_SQL_NF
ON
dbo.tbl_ITEMMAST_NF.CPN = dbo.tbl_SFCWRK_SQL_NF.CPN_NO INNER JOIN dbo.tbl_WORK_CENTR_NF AS tbl_WORK_CENTR_NF
ON
dbo.tbl_SFCWRK_SQL_NF.WC_NBR = tbl_WORK_CENTR_NF.ID INNER JOIN dbo.tbl_WIPOPER_NF
ON
dbo.tbl_SFCWRK_SQL_NF.ID = dbo.tbl_WIPOPER_NF.ID
WHERE
dbo.tbl_WIPOPER_NF.SCHED_COMP_DATE <= DATEADD(m, 2, GETDATE())
AND
(
dbo.tbl_WIPOPER_NF.OPER_STATUS <> 'C'
OR
--dbo.tbl_WIPOPER_NF.OPER_STATUS IS NULL OR dbo.tbl_WIPOPER_NF.OPER_STATUS = ''
--Replace the above statement with the following...
COALESCE(dbo.tbl_WIPOPER_NF.OPER_STATUS, N'') = N''
)
AND
tbl_WORK_CENTR_NF.WAREHOUSE = '02'
AND
dbo.tbl_WIPOPER_NF.WORK_CENTER_NBR IN ('20005', '20010', '20020', '20030', '20040', '20060','20110')
AND
dbo.tbl_ITEMMAST_NF.ITEM_NBR NOT LIKE 'A%'
AND
--CASE WHEN tbl_SFCWRK_SQL_NF.ORDQTY IS NULL THEN 0 ELSE CONVERT(decimal(10, 5), tbl_SFCWRK_SQL_NF.ORDQTY) END <> 0
--I would change the above statement to this...
COALESCE(tbl_SFCWRK_SQL_NF.ORDQTY, 0) <> 0
--AND
--CASE WHEN tbl_SFCWRK_SQL_NF.ORDQTY IS NULL THEN 0 ELSE CONVERT(decimal(10, 5), tbl_SFCWRK_SQL_NF.ORDQTY) END <> 0
--The above statement is a duplicate!
ORDER BY
dbo.tbl_SFCWRK_SQL_NF.WODUEDT DESC