【问题标题】:SQL Server update statement performanceSQL Server 更新语句性能
【发布时间】:2017-08-12 11:48:40
【问题描述】:

我在优化 SQL 查询以进行数据清理时遇到问题。

事实上,我有一个表,它是多个特殊字符和单词的一种参考。我们就叫它ABNORMAL(ID,PATTERN)

我还有另一个表 INDIVIDUALS 包含一个列 (NAME),我想通过删除表 ABNORMAL 中存在的所有字符来清理它。

目前,我已尝试使用更新语句,但不确定是否有更好的方法。

接近一

使用 while 循环将包含来自 ABNORMALS 的所有字符替换为空白 '' 并使用内置的 REPLACE 进行一次更新

DECLARE @REPLACE_EXPRESSION  nvarchar(max) ='REPLACE(NAME,'''','''')'
DECLARE @i int  = 1
DECLARE @nbr int = (SELECT COUNT(*) FROM ABNORMAL) 
-- CURRENT_CHARAC
DECLARE @CURRENT_CHARAC nvarchar(max) 
-- NEW REPLACE EXPRESSION TO IMBRICATE INTO THE REPLACE EXPRESSION VARIABLE
DECLARE @CURR_REP NVARCHAR(max)
-- STRING TO BUILD AN SQL QUERY CONTAINING THE REPLACE EXPRESSION
DECLARE @UPDATE_QUERY nvarchar(max) 
WHILE @i < @nbr
BEGIN 
    SELECT @CURRENT_CHARAC=PATTERN FROM CLEANSING_STG_PRISM_FRA_REF_UNSIGNIFICANT_VALUES WHERE ID_PATTERN=@i ;
    SET @REPLACE_EXPRESSION = REPLACE(@REPLACE_EXPRESSION ,'NAME','REPLACE(NAME,'+''''+@CURRENT_CHARAC+''''+','''')')
    set @i=@i+1
END
SET @UPDATE_QUERY = 'UPDATE INDIVIDUAL  SET NAME ='+ @REPLACE_EXPRESSION
EXEC sp_executesql @UPDATE_QUERY

方法二

使用 while 循环选择每个异常字符,并使用包含要删除的字符的替换进行更新:

DECLARE @i int  = 1
DECLARE @nbr int = (SELECT COUNT(*) FROM ABNORMAL) 
-- CURRENT_CHARAC
DECLARE @CURRENT_CHARAC nvarchar(max) 
-- STRING TO BUILD AN SQL QUERY CONTAINING THE REPLACE EXPRESSION
DECLARE @UPDATE_QUERY nvarchar(max) 
WHILE @i < @nbr
BEGIN 
    SELECT @CURRENT_CHARAC=PATTERN FROM CLEANSING_STG_PRISM_FRA_REF_UNSIGNIFICANT_VALUES WHERE ID_PATTERN=@i ;
    UPDATE INDIVIDUAL 
    SET NAME = REPLACE(NAME,@CURRENT_CHARAC,'')
    SET @i=@i+1
END

我已经针对 200 万条记录测试了这两种方法,我发现第一种方法比第二种方法更快。我想知道您是否已经尝试过类似的和新的(更好的)想法。

【问题讨论】:

    标签: sql sql-server performance


    【解决方案1】:

    如果您使用SQL Server 2017,您可以使用TRANSLATE 并避免使用动态SQL:

    SELECT i.*
      , REPLACE(TRANSLATE(i.NAME, f, REPLICATE('!', s.l)), '!', '') AS cleansed
    FROM INDIVIDUALS i
    OUTER APPLY (SELECT STRING_AGG(PATTERN, '') AS f
                       ,LEN(STRING_AGG(PATTERN,'')) AS l
                 FROM ABNORMAL) AS s
    

    DBFiddle Demo


    无论如何,第一种方法更好,因为你只做一个UPDATE,第二种方法你一次删除一个字符(所以你会有多个UPDATE)。

    我还将使用这两种方法跟踪事务日志的增长。

    【讨论】:

    • 您好,感谢您的反馈。不幸的是,我使用的是 sql server 2016。但是您能否澄清一下“跟踪事务日志”是什么意思?这如何优化我的查询?
    【解决方案2】:

    如果要清理的字符不多,那么这个技巧可能会奏效。

    基本上,您构建 1 个大更新语句,用要删除的字符替换表中的每个值。

    示例代码:

    测试数据(使用临时表)

    create table #ABNORMAL_CHARACTERS (id int identity(1,1), chr varchar(30));
    insert into #ABNORMAL_CHARACTERS (chr) values ('!'),('&'),('#');
    
    create table #INDIVIDUAL (id int identity(1,1), name varchar(30));
    insert into #INDIVIDUAL (name) values ('test 1 &'),('test !&#2'),('test 3');
    

    代码:

    declare @FieldName varchar(30) = 'name';
    declare @Replaces varchar(max) = @FieldName;
    declare @UpdateSQL varchar(max);
    
    select @Replaces = concat('replace('+@Replaces+', ', ''''+chr+''','''')') from #ABNORMAL_CHARACTERS order by id;
    
    set @UpdateSQL = 'update #INDIVIDUAL 
    set name = '+@Replaces + ' 
    where exists (select 1 from #ABNORMAL_CHARACTERS where charindex(chr,name)>0)';
    
    exec (@UpdateSQL);
    
    select * from #INDIVIDUAL;
    

    一个测试here on rextester

    如果您有一个可以进行正则表达式替换的 UDF。 例如here
    那么@Replaces 变量可以简化为只有 1 个 RegexReplace 函数和一个模式。

    【讨论】:

      猜你喜欢
      • 2015-07-27
      • 2013-07-06
      • 2016-12-21
      • 2011-01-11
      • 2021-12-03
      • 1970-01-01
      • 1970-01-01
      • 2018-07-19
      • 2013-02-11
      相关资源
      最近更新 更多