LTRIM(RTRIM(COALESCE(TextField,'')))不好吗?

时间:2009-04-20 16:08:39

标签: sql sql-server performance tsql

我有一个非常高流量的表,其中char(50)字段包含多个索引。这个char(50)字段允许NULLS,在这种情况下,NULL值被认为与我的非NULL,零长度字符串相同。

我也忽略了领先&尾随空格,虽然我在插入数据之前擦除了数据,但它也可以通过我无法控制的方式插入。

我有一个用于将数据从一个表复制到主表的sproc,它需要具有高性能。我需要在插入新数据之前删除重复记录,并且我正在使用所讨论的方法in this thread来执行删除。

我的删除语句如下(简化):

delete masterTable
from masterTable t
    join incomingDataTable inc on
    (
        LTRIM(RTRIM(COALESCE(inc.TextField,''))) = 
             LTRIM(RTRIM(COALESCE(t.TextField,'')))
    )
where LTRIM(RTRIM(COALESCE(t.TextField,''))) <> ''  

I have read构造像LTRIM(RTRIM(...))是不好的。我的删除声明可以改进,如果是,如何改进?

编辑:为了澄清,TextField确实参与了两个表的索引。 EDIT2: TextField在两个表中定义为char(50)。它不是TEXT类型。

6 个答案:

答案 0 :(得分:8)

你需要:

  1. 使用表达式masterTableLTRIM(RTRIM(COALESCE(TextField,'')))上创建计算列
    • 在此列上构建索引并
    • 在联接中使用此列。
  2. 现在设计表的方式使得这个查询对索引友好是不可能的。

    如果您无法更改表格结构但可以估算LEADING个空格的数量,则可以使用here所述的方法。

    然而,这个解决方案远不如在计算列上创建索引那么有效。

答案 1 :(得分:4)

这很糟糕,因为你的JOIN必须扫描整个索引,这是因为你的条件不是 SARGable

您是否也确定是TEXT数据类型?最后我检查过你不能对Text数据类型列使用LTRIM或RTRIM吗?

响应对varchar注释的char,运行此

declare @v varchar(50),@v2 char(50)
select @v ='a',@v2 = 'a'

select datalength(@v),datalength(@v2)

答案 2 :(得分:3)

我建议将该数据类型更改为VARCHAR(50) - 最多约10个字符,CHAR(x)可能有意义,因为它更快并且开销更少 - 但是有50个字符,除非所有列都完全最多使用50个字符,这是一个主要的开销,特别是因为此列也用于索引。

将其更改为VARCHAR(50)可能会显着减少表所需的空间(取决于您的数据量以及实际使用的50个字符中的多少),并且所涉及的所有索引也会得到很多更小 - 再加上你不再需要这个COALESCE,LTRIM,RTRIM东西: - )

马克

答案 3 :(得分:2)

我认为在SQL Server中你可以将填充字符串与非填充字符串相匹配,从而节省了自己在LTRIM / RTRIM上的工作量,但是我不是100%...

但是,整理数据是ETL的一部分,需要在数据到达目的地之前完成。您可能会在大型数据集上发现创建数据的临时副本,重新处理,索引,然后执行所需的匹配更快。

答案 4 :(得分:2)

我相信SQLMenace是正确的。

如何向表中添加 INSERT / UPDATE触发器以确保该列上没有空格?

如果列是VARCHAR,SQL Server将自动忽略结束空格。虽然领先的空白仍然很重要。

实际上,在执行JOIN之前,SQL Server是否会自动将两列填充到CHAR(50)? (牵连转换。)

答案 5 :(得分:2)

如果每次使用时都必须修剪数据,那么这不应该是char数据类型,而是varchar数据类型。每次查询字段时都必须使用函数,数据库设计出现问题。

您可能会发现此讨论很有帮助: Is the CHAR datatype in SQL obsolete? When do you use it?