[英]SQL 2005 Query Optimisation
我有一個SQL 2005表,包含大約一千萬條記錄(dbo.Logs)。
我有另一個表dbo.Rollup,該表將不同的dbo.Logs.URL匹配到第三個表dbo.Files中的FileId列。 dbo.Rollup表構成了我們稍后階段運行的各種匯總報告的基礎。
到目前為止,我遇到的問題是有效填充dbo.Rollup。
根據定義,dbo.Logs可能有成千上萬的行,它們共享相同的URL字段值。 在我們的應用程序中,一個URL可以與一個dbo.Files.FileId匹配。 IE dbo.Logs.URL和dbo.Files.FileId之間存在多對一的關系(我們解析dbo.Logs的值來確定給定URL的適當FileId)。
我的目標是顯着減少運行三個存儲過程中的第一個所花費的時間,以便從原始日志數據中創建有意義的統計信息。
我需要的是一個具體示例,說明如何將這個SQL查詢重構為更加有效的方法:
sp-Rollup-Step1:
INSERT INTO dbo.Rollup ([FileURL], [FileId])
SELECT
logs.RequestedFile As [URL],
FileId = dbo.fn_GetFileIdFromURL(l.RequestedFile, l.CleanFileName)
FROM
dbo.Logs l (readuncommitted)
WHERE
NOT EXISTS (
SELECT
FileURL
FROM
dbo.Rollup
WHERE
FileUrl = RequestedFile
)
fn_GetFileIdFromURL() :
CREATE FUNCTION [dbo].[fn_GetFileIdFromURL]
(
@URL nvarchar(500),
@CleanFileName nvarchar(255)
)
RETURNS uniqueidentifier
AS
BEGIN
DECLARE @id uniqueidentifier
if (exists(select FileURL from dbo.[Rollup] where [FileUrl] = @URL))
begin
-- This URL has been seen before in dbo.Rollup.
-- Retrieve the FileId from the dbo.Rollup table.
set @id = (select top 1 FileId from dbo.[Rollup] where [FileUrl] = @URL)
end
else
begin
-- This is a new URL. Hunt for a matching URL in our list of files,
-- and return a FileId if a match is found.
Set @id = (
SELECT TOP 1
f.FileId
FROM
dbo.[Files] f
INNER JOIN
dbo.[Servers] s on s.[ServerId] = f.[ServerId]
INNER JOIN
dbo.[URLs] u on
u.[ServerId] = f.[ServerId]
WHERE
Left(u.[PrependURLProtocol],4) = left(@URL, 4)
AND @CleanFileName = f.FileName
)
end
return @id
END
關鍵注意事項:
根據我自己的觀察,到目前為止,查詢中最慢的部分似乎是存儲過程:“ NOT EXISTS”子句(在這一點上,我不確定這是否會持續刷新表)。
我正在尋找一種特定的解決方案(使用偽代碼或通過修改此處顯示的過程提供示例)-答案將被授予提供該解決方案的人!
在此先感謝您提供的任何幫助。
/理查德。
簡短的答案是您在這里有一個游標。 每行輸出都會運行標量UDF。
udf可以是派生表上的2個LEFT JOIN。 粗略的輪廓:
...
COALESCE (F.xxx, L.xxx) --etc
...
FROM
dbo.Logs l (readuncommitted)
LEFT JOIN
(select DISTINCT --added after comment
FileId, FileUrl from dbo.[Rollup]) R ON L.FileUrl = R.FileUrl
LEFT JOIN
(SELECT DISTINCT --added after comment
f.FileId,
FileName ,
left(@PrependURLProtocol, 4) + '%' AS Left4
FROM
dbo.[Files] f
INNER JOIN
dbo.[Servers] s on s.[ServerId] = f.[ServerId]
INNER JOIN
dbo.[URLs] u on
u.[ServerId] = f.[ServerId]
) F ON L.CleanFileName = R.FileName AND L.FileURL LIKE F.Left4
...
由於udf的工作方式,我也不確定您是否需要NOT EXISTS。 如果這樣做,請確保對列進行索引。
我認為您的熱點位於:
Left(u.[PrependURLProtocol],4) = left(@URL, 4)
這將導致服務器對url表進行掃描。 您不應在join子句中的字段上使用函數。 嘗試將其重寫為類似
... where PrependURLProtocol like left(@URL, 4) +"%"
並確保您在該字段上有一個索引。
INSERT INTO dbo.Rollup ([FileURL], [FileId])
SELECT
logs.RequestedFile As [URL],
FileId = dbo.fn_GetFileIdFromURL(l.RequestedFile, l.CleanFileName)
FROM dbo.Logs l (readuncommitted) LEFT OUTER JOIN dbo.Rollup
on FileUrl = RequestedFile
WHERE FileUrl IS NULL
這里的邏輯是,如果給定的FileUrl不存在dbo.Rollup,則左外部聯接將變為null。 現在,NOT EXISTS變為IS NULL,這更快。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.