SQL 2005查询优化

时间:2009-09-22 13:13:54

标签: sql sql-server-2005

我有一个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

主要考虑因素:

  • dbo.Rollup应该只包含dbo.tLogs中找到的每个DISTINCT /唯一URL的一个条目。
  • 我想省略记录插入dbo。[Rollup],其中FileId为NULL。

在我自己的观察中,到目前为止,查询中最慢的部分似乎是存储过程:“NOT EXISTS”子句(此时我不确定是否继续刷新表)。

我正在寻找一个特定的解决方案(使用伪代码或修改我在此处显示的程序的示例) - 答案将颁发给提供它的人!

提前感谢您提供的任何帮助。

/理查德。

3 个答案:

答案 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,速度更快。