SQL替换语句太慢了

时间:2014-03-18 10:31:48

标签: sql sql-server

我有一个替换语句,它做了类似的事情:

SELECT Distinct Forenames, Surname, dbUSNs.DateOfBirth, Datasetname, 
       dbUSNs.MoPIGrade, SourceAddress, VRM, URNs 
FROM Person 
WHERE ( Replace(Replace(Replace(Replace(Replace(Replace(Replace
        (Replace(Replace(Replace(Replace(Replace(Replace(Replace
        (Replace(Replace(Replace(Replace(Replace(Replace(Replace
        (Replace(Replace(Replace(Replace
        (Surname,'/',''''),'?',''''),'',''''),'^',''''),'{',''''),'}',''''),
                '[',''''),']',''''),';',''''),'$',''''),'=',''''),'*',''''),
                '#',''''),'|',''''),'&',''''),'@',''''),'\',''''),'<',''''),
                '>',''''),'(',''''),')',''''),'+',''''),',',''''),'.',''''),
                ' ','''') LIKE 'OREILLY%')

因此即使OReilly通过,也会找到O'Reilly。但是,这太慢了。是否有更好的方法来接近它?

6 个答案:

答案 0 :(得分:3)

问题不在于REPLACE&#34;太慢&#34;,但是根本使用它会使查询的一部分不可分析,这意味着它不能使用索引。

Wikipedia: Sargable

基本上,您从上到下强制执行tablescan / indexscan。最重要的是,你有REPLACE的开销。

如果您希望此查询快速运行,我会执行以下操作之一:

  • 创建一个包含可搜索文本版本的Surname
  • 的附加列
  • 使用这些REPLACE函数
  • 创建索引的物化视图

答案 1 :(得分:2)

如果您只想删除所有特殊字符,则可以更轻松地指定有效字符并使用函数执行清理。

这将向您展示如何将字符串清除为字母数字字符和空格'%[^a-z0-9 ]%'

DECLARE @Temp nvarchar(max) ='O''Rielly la/.das.d,as/.d,a/.da.sdo23eu89038 !£$$'

SELECT @Temp

DECLARE @KeepValues AS VARCHAR(50) = '%[^a-z0-9 ]%'
WHILE PatIndex(@KeepValues, @Temp) > 0
    SET @Temp = Stuff(@Temp, PatIndex(@KeepValues, @Temp), 1, '')
SELECT @Temp

哪会返回:ORielly ladasdasdadasdo23eu89038

所以你可以写一个函数:

CREATE FUNCTION [dbo].[RemoveNonAlphaCharacters](@Temp VARCHAR(1000))
RETURNS VARCHAR(1000)
AS
BEGIN
    DECLARE @KeepValues AS VARCHAR(50) = '%[^a-z0-9 ]%'
    WHILE PatIndex(@KeepValues, @Temp) > 0
        SET @Temp = Stuff(@Temp, PatIndex(@KeepValues, @Temp), 1, '')

    RETURN @Temp
END

然后简单地称之为:

SELECT * 
FROM Person 
WHERE [dbo].[RemoveNonAlphaCharacters](Surname) LIKE 'OREILLY%'

如果您不想要空格,只需将其更改为:'%[^a-z0-9]%'

答案 2 :(得分:0)

试试这个:

创建要拆分的功能:

create function [dbo].[Split](@String varchar(8000), @Delimiter char(1))       
returns @temptable TABLE (items varchar(8000))       
as       
begin       
    declare @idx int       
    declare @slice varchar(8000)       

    select @idx = 1       
        if len(@String)<1 or @String is null  return       

    while @idx!= 0       
    begin       
        set @idx = charindex(@Delimiter,@String)       
        if @idx!=0       
            set @slice = left(@String,@idx - 1)       
        else       
            set @slice = @String       

        if(len(@slice)>0)  
            insert into @temptable(Items) values(@slice)       

        set @String = right(@String,len(@String) - @idx)       
        if len(@String) = 0 break       
    end   
return       
end

在where where子句中使用:

WHERE ((REPLACE(Surname, items, '') FROM dbo.Split('/,?,^,{,},[,],;,$,=,*,#,|,&,@,\,<,>,(,),+,.')) LIKE 'OREILLY%')

答案 3 :(得分:0)

一般方法 - 是的。

  • 创建另一个字段(NameNormalized)
  • 运行触发器,只要名称更新,就会设置字段。
  • 然后您可以对该字段(可以有索引)运行搜索。

基本上整个替换狂欢使整个事物不可索引,所以更好的方法是存储规范化的值并允许快速查找。

哦,并评估是否需要明确的 - 这是另一个缓慢的减速。

答案 4 :(得分:0)

SELECT Distinct Forenames, Surname, dbUSNs.DateOfBirth, Datasetname, 
       dbUSNs.MoPIGrade, SourceAddress, VRM, URNs 
FROM Person 
WHERE Surname LIKE 'O[/?^{}[];$=*#|@\<>()+.]R[/?^{}[];$=*#|@\<>()+.]E[/?^{}[];$=*#|@\<>()+.]I[/?^{}[];$=*#|@\<>()+.]L[/?^{}[];$=*#|@\<>()+.]L[/?^{}[];$=*#|@\<>()+.]Y%')

答案 5 :(得分:0)

如果您想使用SUB STRING和While

删除所有特殊字符
DECLARE @str VARCHAR(100),@Len INT,@Pos INT = 1,@char char(1),@results varchar(100)
SET @str = 'O''Rielly la/.das.d,as/.d,a/.da.sdo23eu89038 !£$$'
SET @Len = LEN(@str)
Set @results = ''
WHILE @Pos < @Len
BEGIN 
SET @char = SUBSTRING(@str,@Pos,1)
IF @char like '[a-z0-9]' or @char = ' '
BEGIN
SET @results = @results + @char
END
SET @Pos = @Pos + 1
END
select @results