我有一个SQL 2005表,包含大约1000万条记录(dbo.Logs)。
我有另一个表,dbo.Rollup将不同的dbo.Logs.URL与第三个表dbo.Files中的FileId列匹配。 dbo.Rollup表构成了我们在稍后阶段运行的各种汇总报告的基础。
现在我只想说,我遇到的问题是有效填充dbo.Rollup。
根据定义,dbo.Logs可能有数万行,它们共享相同的URL字段值。在我们的应用程序中,一个URL可以与一个dbo.Files.FileId匹配。 I.E. dbo.Logs.URL和dbo.Files.FileId之间存在多对一关系(我们解析dbo.Logs的值以确定给定URL的适当FileId)。
我的目标是显着减少为了从原始日志数据创建有意义的统计信息而运行的三个存储过程中的第一个所花费的时间。
我需要的是如何重构此SQL查询以提高效率的具体示例:
SP-汇总-步骤1:
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”子句(此时我不确定是否继续刷新表)。
我正在寻找一个特定的解决方案(使用伪代码或修改我在此处显示的程序的示例) - 答案将颁发给提供它的人!
提前感谢您提供的任何帮助。
/理查德。
答案 0 :(得分:2)
简短的回答是你在这里有一个游标。标量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。如果这样做,请确保列已编制索引。
答案 1 :(得分:1)
我认为您的热点位于此处:
Left(u.[PrependURLProtocol],4) = left(@URL, 4)
这将导致服务器对url表进行扫描。您不应该在join子句中的字段上使用函数。尝试将其重写为类似
的内容... where PrependURLProtocol like left(@URL, 4) +"%"
并确保你在该领域有一个索引。
答案 2 :(得分:0)
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,速度更快。