2017-02-20 70 views
0

這個問題的關鍵部分是'最佳',意思是最快的返回時間。我有幾張有我想要的信息的表格。編寫查詢本身並不麻煩,只是試圖確定獲取信息的最快方式。如何優化從多個表中獲取記錄

  • 審計(這是主表我想從信息)
  • 訂單(其餘的都是表我想從有限的數據)
  • 喬布斯
  • 現金

的事情,他們共同點是一個賬戶,因此是一個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條記錄,然後如果它們匹配,則一次填充一條記錄。

+0

讓我看看我是否正確:「審計」表中的「RecordID」字段可以是一個Order,Job或Credit,並且它們唯一共享的是「AccountID」字段? –

+1

看起來很有趣。想到的一點是使用'union all'而不是'union'。這將跳過'union'的額外排序和重複數據刪除。 – SqlZim

+0

你使用的是什麼版本的sql server? 'select @@ version' – SqlZim

回答

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以提高性能。

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優化器相當不錯。很容易找到花費最少的查詢,但與最快的查詢並不完全相同。

如果您通常對於某個賬戶的訂單或工作非常少,那麼您將加入的記錄非常少,只能加入一次,而不是原來的兩次。

考慮[審計]表中RecordType的選擇性。如果Order和Job包含大部分記錄,那麼對RecordType添加索引幾乎沒有好處。據推測,訂單和工作都有一個針對AccountID的索引?

考慮在表格模式中明確表示。 dbo.Audits,Sales.orders等。查詢引擎必須在運行時進行比較,這只是一件小事。

SQL Server上的性能測試在共享環境中可能有點痛苦。我發現使用SQL Profiler可以很好地說明我的查詢和當時正在運行的任何事情,並且它會給你所有你想要的時間。

如果您在測試服務器是否安靜時記住DBCC DROPCLEANBUFFERS將在每次運行後清空緩衝區緩存,以便您可以清楚地瞭解查詢將如何從寒冷中執行。

如果您的生產箱與您的測試箱是不同的規格,那麼您就隱藏起來了。具有大量RAM和共享存儲的多核服務器對典型的DEV工作站的性能會有所不同,特別是如果您同時在其上運行多個任務時。

相關問題