Zoi*_*nky 7 sql-server sql-server-2014
我们的数据库中有 12 种类型的费用,其中一些有相当不同的数据减去金额字段。我们在应用程序和报告中有多个地方需要单个和多个费用总计以及每个费用类型和总计的计数。最后,我们希望所有这些调用都有一个视图,但可以使用存储过程。
我们为此查看了多种替代方案,发现 CTE 允许我们在不使用临时表的情况下获取所需的所有数据。使用连接不起作用,因为无论我们尝试什么,我们都看到记录被复制或删除。
我附上了费用表的一个子集和包含 CTE 的查询。有没有人有比这更好的选择?更快的东西?我们是否适当地接近这种“扁平化”?
请注意,无论是 View 还是 Proc,此查询的执行计划都是相同的,并且 Proc 的运行时间似乎是原来的两倍。
下面是代码
WITH pe AS
(
SELECT
EventRegistrationId
,sum(AmountPaid) as AmountPaidTotal
,sum(CommercialValueAmount) as CommercialValueAmountTotal
,count(1) as ExpenseCount
FROM PettyExpenses
WHERE IsDisputed = 0 AND IsUndisputed = 0
group by EventRegistrationId
),hpe AS
(
SELECT
EventRegistrationId
,sum(AmountPaid) as AmountPaidTotal
,sum(CommercialValueAmount) as CommercialValueAmountTotal
,count(1) as ExpenseCount
FROM HirePremisesExpenses
WHERE IsDisputed = 0 AND IsUndisputed = 0
group by EventRegistrationId
), ae AS
(
SELECT
EventRegistrationId
,sum(AmountPaid) as AmountPaidTotal
,sum(CommercialValueAmount) as CommercialValueAmountTotal
,count(1) as ExpenseCount
FROM AdvertisingExpenses
WHERE IsDisputed = 0 AND IsUndisputed = 0
group by EventRegistrationId
), se AS
(
SELECT
EventRegistrationId
,sum(AmountPaid) as AmountPaidTotal
,sum(CommercialValueAmount) as CommercialValueAmountTotal
,count(1) as ExpenseCount
FROM ServiceExpenses
WHERE IsDisputed = 0 AND IsUndisputed = 0
group by EventRegistrationId
), gse AS
(
SELECT
EventRegistrationId
,sum(AmountPaid) as AmountPaidTotal
,sum(CommercialValueAmount) as CommercialValueAmountTotal
,count(1) as ExpenseCount
FROM GoodsSuppliedExpenses
WHERE IsDisputed = 0 AND IsUndisputed = 0
group by EventRegistrationId
), thve AS
(
SELECT
EventRegistrationId
,sum(AmountPaid) as AmountPaidTotal
,sum(CommercialValueAmount) as CommercialValueAmountTotal
,count(1) as ExpenseCount
FROM TravelHireVehicleExpenses
WHERE IsDisputed = 0 AND
IsUndisputed = 0
group by EventRegistrationId
)
select
distinct eer.EventRegistrationId
--Petty Expense
,ISNULL(pe.AmountPaidTotal,0) as PettyExpenseAmountPaid
,ISNULL(pe.CommercialValueAmountTotal,0) as PettyExpenseCommercial
,ISNULL(pe.ExpenseCount,0) as PettyExpenseCount
--Hire On Premise Expense
,ISNULL(hpe.AmountPaidTotal,0) as HireOnPremisesExpenseAmountPaid
,ISNULL(hpe.CommercialValueAmountTotal,0) as HireOnPremisesExpenseCommercial
,ISNULL(hpe.ExpenseCount,0) as HireOnPremisesExpenseCount
--Advertising Expense
,ISNULL(ae.AmountPaidTotal,0) as AdvertisingExpenseAmountPaid
,ISNULL(ae.CommercialValueAmountTotal,0) as AdvertisingExpenseCommercial
,ISNULL(ae.ExpenseCount,0) as AdvertisingExpenseExpenseCount
--Services Expense
,ISNULL(se.AmountPaidTotal,0) as ServiceExpenseAmountPaid
,ISNULL(se.CommercialValueAmountTotal,0) as ServiceExpenseCommercial
,ISNULL(se.ExpenseCount,0) as ServiceExpenseExpenseCount
--Goods Supplied Expense
,ISNULL(gse.AmountPaidTotal,0) as GoodsSuppliedExpenseAmountPaid
,ISNULL(gse.CommercialValueAmountTotal,0) as GoodsSuppliedExpenseCommercial
,ISNULL(gse.ExpenseCount,0) as GoodsSuppliedExpenseExpenseCount
--Travel and Vehicle Expense
,ISNULL(thve.AmountPaidTotal,0) as TravelVehicleExpenseAmountPaid
,ISNULL(thve.CommercialValueAmountTotal,0) as TravelVehicleExpenseCommercial
,ISNULL(thve.ExpenseCount,0) as TravelVehicleExpenseExpenseCount
--All Expenses
,ISNULL(pe.AmountPaidTotal,0)
+ ISNULL(hpe.AmountPaidTotal,0)
+ ISNULL(ae.AmountPaidTotal,0)
+ ISNULL(se.AmountPaidTotal,0)
+ ISNULL(gse.AmountPaidTotal,0)
+ ISNULL(thve.AmountPaidTotal,0) as AllExpenseAmountPaidTotal
,ISNULL(pe.CommercialValueAmountTotal,0)
+ ISNULL(hpe.CommercialValueAmountTotal,0)
+ ISNULL(ae.CommercialValueAmountTotal,0)
+ ISNULL(se.CommercialValueAmountTotal,0)
+ ISNULL(gse.CommercialValueAmountTotal,0)
+ ISNULL(thve.CommercialValueAmountTotal,0) as AllExpenseCommercialValueTotal
,ISNULL(pe.ExpenseCount,0)
+ ISNULL(hpe.ExpenseCount,0)
+ ISNULL(ae.ExpenseCount,0)
+ ISNULL(se.ExpenseCount,0)
+ ISNULL(gse.ExpenseCount,0)
+ ISNULL(thve.ExpenseCount,0) as AllExpenseCount
from EventRegistrations eer
left join pe on pe.EventRegistrationId = eer.EventRegistrationId
left join hpe on hpe.EventRegistrationId = eer.EventRegistrationId
left join ae on ae.EventRegistrationId = eer.EventRegistrationId
left join se on se.EventRegistrationId = eer.EventRegistrationId
left join gse on gse.EventRegistrationId = eer.EventRegistrationId
left join thve on thve.EventRegistrationId = eer.EventRegistrationId
Run Code Online (Sandbox Code Playgroud)
更新:
这是为那些有兴趣看到它的人插入的数据库模式。
使用 SQL Server 2014 标准,我将 db 架构/插入更改为一个文件(此处为大),其中包含更多插入以及上传的执行计划和结果(2 张图像并排显示所有返回的列)
\n\n\n有人有比这更好的选择吗?有更快的东西吗?
\n
您的原始查询将对所有 6 个表进行表扫描。
\n\n您可以删除distinct eer.EventRegistrationId
并使用GROUP BY eer.EventRegistrationId
,其余一切保持不变。
以下索引将帮助您避免TABLE SCAN
并执行以下操作INDEX SEEK
:
create nonclustered index [nc_PettyExpenses] on [dbo].[PettyExpenses] (\n [IsDisputed]\n ,[IsUndisputed]\n ) include (\n EventRegistrationId\n ,AmountPaid\n ,CommercialValueAmount\n )\ngo\n\ncreate nonclustered index [nc_HirePremisesExpenses] on [dbo].[HirePremisesExpenses] (\n [IsDisputed]\n ,[IsUndisputed]\n ) include (\n EventRegistrationId\n ,AmountPaid\n ,CommercialValueAmount\n )\ngo\n\ncreate nonclustered index [nc_AdvertisingExpenses] on [dbo].[AdvertisingExpenses] (\n [IsDisputed]\n ,[IsUndisputed]\n ) include (\n EventRegistrationId\n ,AmountPaid\n ,CommercialValueAmount\n )\ngo\n\ncreate nonclustered index [nc_ServiceExpenses] on [dbo].[ServiceExpenses] (\n [IsDisputed]\n ,[IsUndisputed]\n ) include (\n EventRegistrationId\n ,AmountPaid\n ,CommercialValueAmount\n )\ngo\n\ncreate nonclustered index [nc_GoodsSuppliedExpenses] on [dbo].[GoodsSuppliedExpenses] (\n [IsDisputed]\n ,[IsUndisputed]\n ) include (\n EventRegistrationId\n ,AmountPaid\n ,CommercialValueAmount\n )\ngo\n\ncreate nonclustered index [nc_TravelHireVehicleExpenses] on [dbo].[TravelHireVehicleExpenses] (\n [IsDisputed]\n ,[IsUndisputed]\n ) include (\n EventRegistrationId\n ,AmountPaid\n ,CommercialValueAmount\n )\ngo\n\ncreate nonclustered index [nc_EventRegistrations] on dbo.EventRegistrations (EventRegistrationId);\n
Run Code Online (Sandbox Code Playgroud)\n\nOPTION (MAXDOP 1)
+以上索引OPTION (MAXDOP 1)
+以上索引查询计划:
\n\n\n\n统计IO输出
\n\n\n\n\xe2\x95\x94\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xa6\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xa6\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x97\n\xe2\x95\x91 Option \xe2\x95\x91 CPU \xe2\x95\x91 ElapsedTime \xe2\x95\x91\n\xe2\x95\xa0\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xac\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xac\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xa3\n\xe2\x95\x91 Plain - As you posted your code \xe2\x95\x91 16 \xe2\x95\x91 12 \xe2\x95\x91\n\xe2\x95\x91 Without MAXDOP 1 + Indexes \xe2\x95\x91 62 \xe2\x95\x91 11 \xe2\x95\x91\n\xe2\x95\x91 With MAXDOP 1 + Indexes \xe2\x95\x91 0 \xe2\x95\x91 7 \xe2\x95\x91 <== Winner !!\n\xe2\x95\x9a\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xa9\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xa9\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x9d\n
Run Code Online (Sandbox Code Playgroud)\n\n为了完整性,下面是代码:
\n\n/*\ndbcc freeproccache\ndbcc dropcleanbuffers\n\n*/\nset nocount on\nset statistics io on\nset statistics time on;\n\nwith pe\nas (\n select EventRegistrationId\n ,sum(AmountPaid) as AmountPaidTotal\n ,sum(CommercialValueAmount) as CommercialValueAmountTotal\n ,count(1) as ExpenseCount\n from PettyExpenses\n where IsDisputed = 0\n and IsUndisputed = 0\n group by EventRegistrationId\n )\n ,hpe\nas (\n select EventRegistrationId\n ,sum(AmountPaid) as AmountPaidTotal\n ,sum(CommercialValueAmount) as CommercialValueAmountTotal\n ,count(1) as ExpenseCount\n from HirePremisesExpenses\n where IsDisputed = 0\n and IsUndisputed = 0\n group by EventRegistrationId\n )\n ,ae\nas (\n select EventRegistrationId\n ,sum(AmountPaid) as AmountPaidTotal\n ,sum(CommercialValueAmount) as CommercialValueAmountTotal\n ,count(1) as ExpenseCount\n from AdvertisingExpenses\n where IsDisputed = 0\n and IsUndisputed = 0\n group by EventRegistrationId\n )\n ,se\nas (\n select EventRegistrationId\n ,sum(AmountPaid) as AmountPaidTotal\n ,sum(CommercialValueAmount) as CommercialValueAmountTotal\n ,count(1) as ExpenseCount\n from ServiceExpenses\n where IsDisputed = 0\n and IsUndisputed = 0\n group by EventRegistrationId\n )\n ,gse\nas (\n select EventRegistrationId\n ,sum(AmountPaid) as AmountPaidTotal\n ,sum(CommercialValueAmount) as CommercialValueAmountTotal\n ,count(1) as ExpenseCount\n from GoodsSuppliedExpenses\n where IsDisputed = 0\n and IsUndisputed = 0\n group by EventRegistrationId\n )\n ,thve\nas (\n select EventRegistrationId\n ,sum(AmountPaid) as AmountPaidTotal\n ,sum(CommercialValueAmount) as CommercialValueAmountTotal\n ,count(1) as ExpenseCount\n from TravelHireVehicleExpenses\n where IsDisputed = 0\n and IsUndisputed = 0\n group by EventRegistrationId\n )\nselect eer.EventRegistrationId\n --Petty Expense\n ,ISNULL(SUM(case e.src\n when \'pe\'\n then e.AmountPaidTotal\n end), 0) as PettyExpenseAmountPaid\n ,ISNULL(SUM(case e.src\n when \'pe\'\n then e.CommercialValueAmountTotal\n end), 0) as PettyExpenseCommercial\n ,ISNULL(SUM(case e.src\n when \'pe\'\n then e.ExpenseCount\n end), 0) as PettyExpenseCount\n --Hire On Premise Expense\n ,ISNULL(SUM(case e.src\n when \'hpe\'\n then e.AmountPaidTotal\n end), 0) as HireOnPremisesExpenseAmountPaid\n ,ISNULL(SUM(case e.src\n when \'hpe\'\n then e.CommercialValueAmountTotal\n end), 0) as HireOnPremisesExpenseCommercial\n ,ISNULL(SUM(case e.src\n when \'hpe\'\n then e.ExpenseCount\n end), 0) as HireOnPremisesExpenseCount\n --Advertising Expense\n ,ISNULL(SUM(case e.src\n when \'ae\'\n then e.AmountPaidTotal\n end), 0) as AdvertisingExpenseAmountPaid\n ,ISNULL(SUM(case e.src\n when \'ae\'\n then e.CommercialValueAmountTotal\n end), 0) as AdvertisingExpenseCommercial\n ,ISNULL(SUM(case e.src\n when \'ae\'\n then e.ExpenseCount\n end), 0) as AdvertisingExpenseExpenseCount\n --Services Expense\n ,ISNULL(SUM(case e.src\n when \'se\'\n then e.AmountPaidTotal\n end), 0) as ServiceExpenseAmountPaid\n ,ISNULL(SUM(case e.src\n when \'se\'\n then e.CommercialValueAmountTotal\n end), 0) as ServiceExpenseCommercial\n ,ISNULL(SUM(case e.src\n when \'se\'\n then e.ExpenseCount\n end), 0) as ServiceExpenseExpenseCount\n --Goods Supplied Expense\n ,ISNULL(SUM(case e.src\n when \'gse\'\n then e.AmountPaidTotal\n end), 0) as GoodsSuppliedExpenseAmountPaid\n ,ISNULL(SUM(case e.src\n when \'gse\'\n then e.CommercialValueAmountTotal\n end), 0) as GoodsSuppliedExpenseCommercial\n ,ISNULL(SUM(case e.src\n when \'gse\'\n then e.ExpenseCount\n end), 0) as GoodsSuppliedExpenseExpenseCount\n --Travel and Vehicle Expense\n ,ISNULL(SUM(case e.src\n when \'thve\'\n then e.AmountPaidTotal\n end), 0) as TravelVehicleExpenseAmountPaid\n ,ISNULL(SUM(case e.src\n when \'thve\'\n then e.CommercialValueAmountTotal\n end), 0) as TravelVehicleExpenseCommercial\n ,ISNULL(SUM(case e.src\n when \'thve\'\n then e.ExpenseCount\n end), 0) as TravelVehicleExpenseExpenseCount\n --All Expenses\n ,ISNULL(SUM(e.AmountPaidTotal), 0) as AllExpenseAmountPaidTotal\n ,ISNULL(SUM(e.CommercialValueAmountTotal), 0) as AllExpenseCommercialValueTotal\n ,ISNULL(SUM(e.ExpenseCount), 0) as AllExpenseCount\nfrom EventRegistrations eer\nleft join (\n select \'pe\' as src\n ,EventRegistrationId\n ,AmountPaidTotal\n ,CommercialValueAmountTotal\n ,ExpenseCount\n from pe\n\n union all\n\n select \'hpe\' as src\n ,EventRegistrationId\n ,AmountPaidTotal\n ,CommercialValueAmountTotal\n ,ExpenseCount\n from hpe\n\n union all\n\n select \'ae\' as src\n ,EventRegistrationId\n ,AmountPaidTotal\n ,CommercialValueAmountTotal\n ,ExpenseCount\n from ae\n\n union all\n\n select \'se\' as src\n ,EventRegistrationId\n ,AmountPaidTotal\n ,CommercialValueAmountTotal\n ,ExpenseCount\n from se\n\n union all\n\n select \'gse\' as src\n ,EventRegistrationId\n ,AmountPaidTotal\n ,CommercialValueAmountTotal\n ,ExpenseCount\n from gse\n\n union all\n\n select \'thve\' as src\n ,EventRegistrationId\n ,AmountPaidTotal\n ,CommercialValueAmountTotal\n ,ExpenseCount\n from thve\n ) as e on eer.EventRegistrationId = e.EventRegistrationId\ngroup by eer.EventRegistrationId --- we removed the distinct and added a group by clause \noption (maxdop 1)\n\nset statistics io off\nset statistics time off\n
Run Code Online (Sandbox Code Playgroud)\n\n注意:您可以伪造行数和页数<--仅用于教育目的
\n\nUPDATE STATISTICS [dbo].[PettyExpenses] WITH ROWCOUNT = 10000000, pagecount = 10000000\nUPDATE STATISTICS [dbo].[HirePremisesExpenses] WITH ROWCOUNT = 10000000, pagecount = 10000000\nUPDATE STATISTICS [dbo].[AdvertisingExpenses] WITH ROWCOUNT = 10000000, pagecount = 10000000\nUPDATE STATISTICS [dbo].[ServiceExpenses] WITH ROWCOUNT = 10000000, pagecount = 10000000\nUPDATE STATISTICS [dbo].[GoodsSuppliedExpenses] WITH ROWCOUNT = 10000000, pagecount = 10000000\nUPDATE STATISTICS [dbo].[TravelHireVehicleExpenses] WITH ROWCOUNT = 10000000, pagecount = 10000000\n
Run Code Online (Sandbox Code Playgroud)\n