动态查询VS静态查询性能

时间:2017-05-09 12:57:51

标签: sql sql-server sql-server-2012 query-performance dynamicquery

我编写了2个存储过程,根据参数读取相同的数据,一个使用静态查询sp_Order_Read1,另一个使用动态sp_Order_Read2。他们读取了Orders示例数据库中Northwind表的数据;在SQL Server 2012

sp_Order_Read1

create proc sp_Order_Read1 @OrderID int, @page int, @pageLength int
as begin
    if @OrderID is null
    begin
        if @page is not null and @pageLength is not null
            select OrderID, CustomerID, EmployeeID, OrderDate, RequiredDate, ShippedDate, ShipVia, Freight, ShipName, ShipAddress, ShipCity, ShipRegion, ShipPostalCode, ShipCountry
                from Orders o
                order by o.OrderID
                offset (@page - 1) * @pageLength rows
                fetch next @pageLength rows only
        else
            select OrderID, CustomerID, EmployeeID, OrderDate, RequiredDate, ShippedDate, ShipVia, Freight, ShipName, ShipAddress, ShipCity, ShipRegion, ShipPostalCode, ShipCountry
                from Orders o
    end
    else
    begin
        if @page is not null and @pageLength is not null
            select OrderID, CustomerID, EmployeeID, OrderDate, RequiredDate, ShippedDate, ShipVia, Freight, ShipName, ShipAddress, ShipCity, ShipRegion, ShipPostalCode, ShipCountry
                from Orders o
                where o.OrderID = @OrderID
                order by o.OrderID
                offset (@page - 1) * @pageLength rows
                fetch next @pageLength rows only
        else
            select OrderID, CustomerID, EmployeeID, OrderDate, RequiredDate, ShippedDate, ShipVia, Freight, ShipName, ShipAddress, ShipCity, ShipRegion, ShipPostalCode, ShipCountry
                from Orders o
                where o.OrderID = @OrderID
    end
end

sp_Order_Read2

create proc sp_Order_Read2 @OrderID int, @page int, @pageLength int
as begin
    declare @query nvarchar(max) = ''
    if @OrderID is not null
    begin
        declare @OrderIDExpression nvarchar(max)
        if IsNumeric(@OrderID) = 1
            set @OrderIDExpression = @OrderID
        else
            set @OrderIDExpression = '''' + @OrderID + ''''
        set @query += 'declare @OrderID int = ' + @OrderIDExpression + ';
        '
    end
    if @page is not null and @pageLength is not null
    begin
        set @query += 'declare @page int = ' + convert(nvarchar(max), @page) + ';
        declare @pageLength int = ' + convert(nvarchar(max), @pageLength) + ';
        '
    end
    set @query +=
        'select OrderID, CustomerID, EmployeeID, OrderDate, RequiredDate, ShippedDate, ShipVia, Freight, ShipName, ShipAddress, ShipCity, ShipRegion, ShipPostalCode, ShipCountry
            from Orders o'
    if @OrderID is not null
        set @query += '
        where'
    if @OrderID is not null
        set @query += '
        OrderID = @OrderID'
    if @page is not null and @pageLength is not null
        set @query += '
        order by o.OrderID
        offset (@page - 1) * @pageLength rows
        fetch next @pageLength rows only'
    exec(@query)
end

* 请注意,我编写了一个为我生成静态/动态语法的工具,因此写入不是一件大事。

我无法决定哪种语法运行得更快,所以我决定测试它们。我创建了临时表#comparison来保存结果。

create table #comparison
(
    ID int identity,
    One int,
    Two int
)

测试就是这个剧本:

declare @counter int = 1
declare @count int = 50
declare @beginning1 datetimeoffset
declare @end1 datetimeoffset 
declare @beginning2 datetimeoffset
declare @end2 datetimeoffset
while(@counter <= @count)
begin
    set @beginning1 = sysdatetimeoffset()
        exec sp_Order_Read1 null, 5, 50
    set @end1 = sysdatetimeoffset()
    set @beginning2 = sysdatetimeoffset()
        exec sp_Order_Read2 null, 5, 50
    set @end2 = sysdatetimeoffset()
    insert #comparison (One, Two) values (datediff(microsecond, @beginning1, @end1), datediff(microsecond, @beginning2, @end2))
set @counter += 1
end

我跑了5次,每次看完这个查询后的结果:

select count(ID) as [Row Count], (sum(One) - sum(Two)) as [Difference] from #comparison

然后我将测试脚本中的顺序切换为:

declare @counter int = 1
declare @count int = 50
declare @beginning1 datetimeoffset
declare @end1 datetimeoffset 
declare @beginning2 datetimeoffset
declare @end2 datetimeoffset
while(@counter <= @count)
begin
    set @beginning2 = sysdatetimeoffset()
        exec sp_Order_Read2 null, 5, 50
    set @end2 = sysdatetimeoffset()
    set @beginning1 = sysdatetimeoffset()
        exec sp_Order_Read1 null, 5, 50
    set @end1 = sysdatetimeoffset()
    insert #comparison (One, Two) values (datediff(microsecond, @beginning1, @end1), datediff(microsecond, @beginning2, @end2))
set @counter += 1
end

我还运行了5次,每次运行后我都使用相同的查询查看了结果。测试结果如下:

Row Count   Difference
---------------------------
100     439119
200     35963
300     2211699
400     14443
500     -2666605
--Reversed Excution Order--
600     5846095
700     13221704
800     21094312
900     28361390
1000    37526611

结果非常奇怪,对我不满意;所以,如果有人能帮助我决定哪种语法运行得更快,给出令人满意的推理,我会感激不尽。

0 个答案:

没有答案