代码之家  ›  专栏  ›  技术社区  ›  Faiz

SQL中存在很大的性能差异(1小时到1分钟)。你能解释一下原因吗?

  •  0
  • Faiz  · 技术社区  · 16 年前

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

    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秒内处理了一百万条记录,得到了相同的“参数”列值。

    2 回复  |  直到 16 年前
        1
  •  6
  •   Rubens Farias    16 年前

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

        2
  •  2
  •   Cade Roux    16 年前

    即使是确定性标量函数,每行也至少计算一次。如果同一确定性标量函数在同一“行”上使用相同的参数多次出现,我相信只有在这种情况下才会对其进行一次计算-例如,在 CASE WHEN fn_X(a, b, c) > 0 THEN fn_X(a, b, c) ELSE 0 END 或者类似的。

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

    相同的种子值返回相同的值 结果。

    使用指定的种子值调用, RAND()的所有后续调用都会产生 基于种子RAND()的结果 将始终返回相同的序列

    正如您所指出的,我已经开始缓存标量函数结果——甚至可以预先计算标量函数结果表并加入它们。要使标量函数发挥作用,最终必须采取一些措施。不是这样,最好的选择是CLR——显然,它们的性能远远优于SQLUDF。不幸的是,我无法在当前环境中使用它们。

    推荐文章