SQL Server показывает мне разные RowCounts с использованием скалярных функций - PullRequest
2 голосов
/ 12 июля 2011

У меня есть скалярная функция с именем DATEONLY, которая возвращает DATEADD (DD, 0, DATEDIFF (DD, 0, @DATETIME)), вот так:

CREATE FUNCTION [DBO].[DATEONLY] ( @DATETIME DATETIME )
RETURNS DATETIME
BEGIN
    RETURN DATEADD(DD, 0, DATEDIFF(DD, 0, @DATETIME))
END

Когда я выбираю таблицу с помощьюмоя функция, SQL Server Profiler считает большее число RowCounts, чем если бы я использовал непосредственно DATEADD (DD, 0, DATEDIFF (DD, 0, @DATETIME)).

В публичной папке моего Dropxbox вы можете найти скрипт.sql, который может воспроизвести то, о чем я говорю, и вы также можете найти Trace.trc из моего SQL Server Profiler.

script.sql: https://www.dropbox.com/s/gwbh54jqas7fhhc/script.sql

trace.trc: https://www.dropbox.com/s/gwbh54jqas7fhhc/Trace.trc

Просто для упрощения, посмотрите RowCounts ниже.

SELECT DATEADD(DD,0, DATEDIFF(DD,0, INCOMING)) AS DATA, COUNT(*) AS SOULS
FROM HELL
GROUP BY DATEADD(DD,0, DATEDIFF(DD,0, INCOMING))

RowCounts = 6

SELECT DBO.DATEONLY(INCOMING) AS DATA, COUNT(*) AS SOULS
FROM HELL
GROUP BY DBO.DATEONLY(INCOMING)

RowCounts = 32

В моем реальном сценарииэти 32 строки превращаются в миллионы RowCounts.Если они такие же, что происходит ?!Как я могу оптимизировать это, чтобы предотвратить изменение всего моего приложения?

Большое спасибо!

Ответы [ 3 ]

3 голосов
/ 12 июля 2011

Выполнение скалярной пользовательской функции не очень эффективно на сервере sql - по сути, он выполняет отдельный вызов выполнения для каждого вызова, который является каждой строкой в ​​таблице. У Адама Маханича есть хорошая запись на эту тему, которая описывает скалярное выполнение udf и то, как выполнение встроенных табличных функций может быть намного быстрее.

Можно переписать ваш запрос, чтобы использовать вместо этого логику внутри tvf, которую оптимизатор выполняет с использованием того же плана запроса, что и исходный расширенный запрос, и показывает то же RowCounts = 5 во время выполнения.

CREATE FUNCTION [DBO].[DATEONLY2] ( @DATETIME DATETIME ) RETURNS TABLE
AS RETURN SELECT DATEADD(DD, 0, DATEDIFF(DD, 0, @DATETIME)) data

select data, count(*) as souls
from
(SELECT (select data from dbo.dateonly2(incoming)) data
FROM HELL) t
GROUP BY data
1 голос
/ 12 июля 2011

Это потому, что UDF оценивается каждый раз для каждой строки.То, что вы испытываете, описано в сообщении в блоге: http://blogs.msdn.com/b/sqlserverfaq/archive/2009/10/06/performance-benefits-of-using-expression-over-user-defined-functions.aspx

0 голосов
/ 14 июля 2011

Я бы предложил использовать следующий запрос

SELECT DATEADD(DD,0, DATEDIFF(DD,0, INCOMING)) AS DATA, COUNT(*) AS SOULS
FROM HELL
GROUP BY DATEADD(DD,0, DATEDIFF(DD,0, INCOMING))

, вы можете создать индекс для входящего столбца, чтобы избежать снижения производительности.

...