Dynamic Query VS Static Query Performance
Я написал 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
Результаты были довольно странными и неудовлетворительными для меня; поэтому, если бы кто-нибудь мог помочь мне решить, какой синтаксис должен работать быстрее, давая удовлетворительные аргументы, я был бы благодарен.