如何从多个表中优化获取记录

时间:2017-02-20 20:33:09

标签: sql sql-server tsql

这个问题的关键部分是' Optimally'意思是最快的返回时间。我有几张表有我需要的信息。我在编写查询本身时没有遇到任何麻烦,只是在尝试确定获取信息的最快方式时。

  • 审核(这是我想要信息的主要表格)
  • 订单(其余的是我想要有限数据的表格)
  • 工作
  • 积分

他们共同的事情是一个帐户,因此是一个AccountID。我有我正在寻找的AccountID。遗憾的是,审计表没有直接外键到相关帐户表中,从而确定审计记录是否属于我的结果集我必须加入审计表和后续的3个表一个一次检查审核记录是否与我的AccountID相关。

例如

Select a.* from [Audits] a JOIN [Orders] o ON a.RecordID = o.OrderID
where a.RecordType = 'Order' and o.AccountID = @AccountID
union
select a.* from [Audits] a JOIN [Jobs] j on a.RecordID = j.JobID
where a.RecordType = 'Job' and j.AccountID = @AccountID
...

我打算在第一个数据子集上进行下一次获取,然后从次表中填写信息,以便我最初进行有限的命中。我认为这是一个两部分问题,首先是找到属于我的子集的AuditID的最快方法,其次是填写缺失数据的最快方法。任何建议将不胜感激。

编辑1

我现在提出了一个解决方案,但我有兴趣知道是否有任何简单的方法来优化它,所以我会在这里发布它希望它有所帮助进一步澄清问题。如果您发现语法错误,请忽略它们,我试图尽可能多地删除不必要的信息。

Create Table #AuditTemp (columns)
Insert into #AuditTemp a.*, null as [Extra1], null as [Extra2] ...
From [Audits] a 
Left Join [Orders] o ON a.RecordID = o.OrderID
Left Join [Jobs] j ON a.RecordID = j.JobID
Left Join [Credits] c ON a.RecordID = c.CreditID
Where o.AccountID = @AccountID or j.AccountID = @AccountID ...
Order By Time desc
OFFSET @offset ROWS FETCH NEXT @PageSize ROWS ONLY

Update #AuditTemp Set [Extra1] = o.[Column1] ...
From [Orders] Where o.AccountID = @AccountID and #AuditTemp.RecordID = o.OrderID 
...

所以我得到了我需要的20条记录,然后如果它们匹配则一次填写一条。

2 个答案:

答案 0 :(得分:1)

我要做的第一件事就是查看查询的执行计划。可能的替代方案如下所示。

SELECT A.*
FROM [Audits] A

INNER JOIN (
    SELECT OrderID AS RecordID FROM [Orders] WHERE AccountID = @AccountID
    UNION ALL
    SELECT JobID AS RecordID FROM [Jobs] WHERE AccountID = @AccountID
) AS DT
ON A.RecordID = DT.RecordID
WHERE A.RecordType IN ('Order','Job')

另一种方法是将UNION ALL查询转换为公用表表达式。

SQL Server优化器现在相当不错。很容易找到成本最低的查询,但这与最快的查询并不完全相同。

如果您的帐户通常只有很少的订单或工作,那么您将加入极少数记录,只加入一次,而不是原来的两次。

考虑[audits]表中RecordType的选择性。如果Order和Job包含大部分记录,那么为RecordType添加索引几乎没有什么好处。据推测,Order和Jobs有一个针对AccountID的索引?

考虑在表的架构中明确。 dbo.Audits,Sales.orders等。查询引擎在运行时必须进行比较只是少了一点。

SQL Server上的性能测试在共享环境中可能会有点痛苦。我发现使用SQL事件探查器可以很好地指示我的查询和当时正在运行的其他内容,以及它将为您提供所需的所有时间。

如果您正在测试服务器何时安静,请记住DBCC DROPCLEANBUFFERS将在每次运行后清除缓冲区缓存,以便您可以清楚地了解查询将如何执行。

如果您的生产箱与您的测试盒的规格不同,那么您将隐藏起来。具有大量RAM和共享存储的多核服务器将对典型的DEV工作站执行不同的操作,特别是如果您同时在其上运行多个任务。

答案 1 :(得分:1)

如果这是您必须经常做的事情,我建议您从辅助表创建view,并使用它将您的Audit表与您的辅助表连接。

CreateView [dbo].[SecondaryTables]
AS
SELECT OrderID AS RecordID, 'Order' AS RecordType, AccountID
FROM [Orders]
UNION
SELECT JobID AS RecordID, 'Job' AS RecordType, AccountID
FROM [Jobs]
UNION
SELECT CreditID AS RecordID, 'Credit' AS RecordType, AccountID
FROM [Credits]

然后您可以使用此视图加入所需的所有数据

SELECT [all your required fields]
FROM [SecondaryTables] vw
INNER JOIN [Audit] au
ON vw.RecordID = au.RecordID AND vw.RecordType = au.RecordType
LEFT OUTER JOIN [Orders] od
ON vw.RecordID = od.OrderID AND vw.RecordType = 'Order'
LEFT OUTER JOIN [Jobs] jo
ON vw.RecordID = jo.JobID AND vw.RecordType = 'Job'
LEFT OUTER JOIN [Credits] cr
ON vw.RecordID = cr.CreditID AND vw.RecordType = 'Credit'
WHERE vw.AccountID = @AccountID

如果您希望所有表格中的结果(所有结果将始终包含3个表格中的数据),您可以将LEFT OUTER更改为INNER以提高效果。