0

以下查询在标准机器上分别需要 70 分钟和 1 分钟,以获取 100 万条记录。可能的原因是什么?

查询 [01:10:00]

SELECT * 
FROM cdc.fn_cdc_get_net_changes_dbo_PartitionTest(
    CASE WHEN sys.fn_cdc_increment_lsn(0x00)<sys.fn_cdc_get_min_lsn('dbo_PartitionTest')        
        THEN sys.fn_cdc_get_min_lsn('dbo_PartitionTest')        
        ELSE sys.fn_cdc_increment_lsn(0x00) END
    , sys.fn_cdc_get_max_lsn()
    , 'all with mask') 
WHERE __$operation <> 1

修改后的查询 [00:01:10]

DECLARE @MinLSN binary(10)
DECLARE @MaxLSN binary(10)
SELECT @MaxLSN= sys.fn_cdc_get_max_lsn()
SELECT @MinLSN=CASE WHEN sys.fn_cdc_increment_lsn(0x00)<sys.fn_cdc_get_min_lsn('dbo_PartitionTest')     
        THEN sys.fn_cdc_get_min_lsn('dbo_PartitionTest')        
        ELSE sys.fn_cdc_increment_lsn(0x00) END

SELECT * 
FROM cdc.fn_cdc_get_net_changes_dbo_PartitionTest(
        @MinLSN, @MaxLSN, 'all with mask') WHERE __$operation <> 1

[修改的]

我尝试使用类似的函数重新创建场景,以查看是否为每一行评估参数。

CREATE FUNCTION Fn_Test(@a decimal)RETURNS TABLE
AS
RETURN
(
    SELECT @a Parameter, Getdate() Dt, PartitionTest.*
    FROM PartitionTest
);

SELECT * FROM Fn_Test(RAND(DATEPART(s,GETDATE())))

但是对于在 38 秒内处理的一百万条记录,我在“参数”列中得到了相同的值。

4

2 回答 2

6

在您的第一个查询中,您的fn_cdc_increment_lsnfn_cdc_get_min_lsn会为每一行执行。在第二个例子中,只有一次。

于 2009-11-30T12:28:32.797 回答
2

即使是确定性标量函数也至少每行评估一次。如果相同的确定性标量函数在具有相同参数的同一“行”上多次出现,我相信只有这样它才会被评估一次 - 例如在 aCASE WHEN fn_X(a, b, c) > 0 THEN fn_X(a, b, c) ELSE 0 END或类似的东西中。

我认为您的兰德问题是因为您继续重新播种:

重复调用具有相同种子值的 RAND() 会返回相同的结果。

对于一个连接,如果使用指定的种子值调用 RAND(),则 RAND() 的所有后续调用都会根据种子 RAND() 调用产生结果。例如,以下查询将始终返回相同的数字序列。

正如您所指出的,我已经开始缓存标量函数结果 - 甚至预先计算标量函数结果表并加入它们。最终必须做一些事情才能使标量函数执行。不对,最好的选择是 CLR——显然这些远远优于 SQL UDF。不幸的是,我无法在当前环境中使用它们。

于 2009-11-30T13:46:09.783 回答