TSQL“LIKE”还是正则表达式?

时间:2009-01-19 18:21:54

标签: sql-server tsql

我在一个表中有一堆(750K)记录,我必须看到它们在另一个表中。第二个表有数百万条记录,数据是这样的:

来源表
9999-A1B-1234X,中间部分可能超过三位

目标表
DescriptionPhrase9999-A1B-1234X(9 pages) - 是的,parens和话语都在现场。

目前我正在运行.net应用程序,它加载源记录,然后运行并搜索类似的(使用tsql函数)来确定是否有任何记录。如果是,则源表更新为正数。如果没有,记录就不复存在了。

该应用程序每小时处理大约1000条记录。当我在sql server上作为游标sproc执行此操作时,我的速度几乎相同。

任何想法,如果正则表达式或任何其他方法会使它更快?

8 个答案:

答案 0 :(得分:5)

如何在数据库中完成所有工作,而不是将记录拉入.Net应用程序:

UPDATE source_table s SET some_field = true WHERE EXISTS
(
     SELECT target_join_field FROM target_table t 
     WHERE t.target_join_field LIKE '%' + s.source_join_field + '%'
)

这会将查询总数从750k更新查询减少到1次更新。

答案 1 :(得分:3)

首先,如果可能,我会重新设计。最好添加一个包含正确值的列,并能够加入它。如果你仍然需要长的。您可以使用触发器在插入数据时将数据提取到列中。

如果您有可以匹配的数据,则既不需要不能使用索引的'%somestuff%',也不需要两个都是性能杀手的游标。如果您已正确设计,这应该是基于设置的任务。如果设计不好并且无法改变为好的设计,我认为没有好的方法来使用t-SQl获得良好的性能,我会尝试正则表达式路由。不知道有多少不同的prharses和每个的结构,我不能说正则表达式路由是否容易甚至可能。但如果没有重新设计(我强烈建议你这样做),我看不到另一种可能性。

顺便说一句,如果你正在处理那些大的表,我会决定永远不会写另一个游标。它们对性能非常不利,特别是当你开始记录那么大的记录时。通过记录处理学习成套思考。

答案 2 :(得分:3)

使用单个更新(mbeckish的答案)需要注意的一点是,事务日志(如果查询被取消则启用回滚)将是巨大的。这将大大减慢您的查询速度。因此,最好以1,000行或类似的块来处理它们。

此外,条件(b.field如'%'+ a.field +'%')将需要检查(750,000)中每条记录的b(百万)中的每条记录。这相当于超过7500亿字符串比较。不太好。

直觉感觉“索引的东西”也无济于事。索引使事物保持有序,因此第一个字符决定了索引中的位置,而不是您感兴趣的位置。

第一个想法

出于这个原因,我实际上会考虑创建另一个表,并将long / messy值解析为更好的值。一个例子就是从最后一个'('开始)剥离任何文本。(这假设所有值都遵循该模式)这会将查询条件简化为(b .field,如'%'+ a.field)

尽管如此,一个索引在这里也无济于事,因为重要的角色在最后。所以,奇怪的是,以相反的顺序存储两个表的字符可能是值得的。然后,临时表上的索引将被使用。

花费那么多时间似乎非常浪费,但在这种情况下,一个小的好处会产生一个很大的回报。 (例如,几个小时的工作将比较从750亿减半减少到375亿。如果你可以让索引进入游戏,你可以减少这一千倍,这要归功于索引是树搜索,而不仅仅是有序表...)< / p>

第二个想法

假设您确实将目标表复制到临时表中,您还可以通过删除目标表中的匹配记录,以1000块为单位处理它们。 (只有在从目标表中删除有意义的数量时,这才有价值。这样,在检查了所有750,000条记录之后,目标表现在[例如]是它开始时的一半大小。)

编辑:
修改后的第二个想法

  1. 将整个目标表放入临时表中。

  2. 尽可能预处理这些值,以便更快地进行字符串比较,甚至可以使索引进入播放状态。

  3. 一次一个地从源表中循环遍历每条记录。在循环中使用以下逻辑......

    DELETE target WHERE字段LIKE'%'+ @ source_field +'%' IF(@@ row_count = 0)     [无匹配] 其他     [匹配]

  4. 连续删除使得每个循环上的查询更快,并且您只对数据使用一个查询(而不是一个查找匹配,第二个删除匹配)

答案 3 :(得分:1)

试试这个 -

update SourceTable  
set ContainsBit = 1  
from SourceTable t1      
  join (select TargetField from dbo.TargetTable t2) t2   
    on charindex(t1.SourceField, t2.TargetField) > 0

答案 4 :(得分:0)

首先要确保搜索到的表上有该列的索引。第二个是在左侧执行LIKE 而不使用%符号。检查执行计划,看看你是否在每一行都没有进行表扫描。

正如le dorfier正确指出的那样,如果您使用的是UDF,则几乎没有希望。

答案 5 :(得分:0)

有许多方法可以让猫皮肤 - 我认为首先要知道这是一次性操作还是需要定期完成的常规任务是很重要的。

不知道你问题的所有细节,如果是我,这是一次性的(或不经常的操作,听起来像是),我可能只从两个中提取相关的字段表包括源表中的主键,并将它们作为文本文件导出到本地计算机。文件大小可能会比数据库中的完整表小得多。

我在快速机器上本地运行它,使用类似'C'/ C ++或其他具有原始处理能力的“轻量级”语言编写的例程,并写出一个“匹配”的主键表,然后我将加载回sql server并将其用作更新查询的基础(即更新源表,其中id为临时表中的select id)。

你可能花了几个小时编写例程,但是它会在你看到sql的一小部分时间内运行。

通过你的sql声音,你可能会尝试对数百万个记录表进行750,000次表扫描。

告诉我们有关此问题的更多信息。

答案 6 :(得分:0)

圣烟,有什么好的回应!

系统在断开连接的网络上,所以我无法复制粘贴,但这里是重新输入

当前UDF:

Create function CountInTrim 
(@caseno varchar255)
 returns int
as 
Begin
declare @reccount int
select @reccount = count(recId) from targettable where title like '%' + @caseNo +'%'
return @reccount
end

基本上,如果有记录计数,则匹配,.net应用程序更新记录。基于游标的sproc具有相同的逻辑。

此外,这是一次性过程,确定传统记录/案例管理系统中的哪些条目已成功迁移到新系统中,因此我无法重新设计任何内容。当然,任何一个系统的开发人员都不再可用,虽然我有一些SQL经验,但我绝不是专家。

我从旧系统必须制作源表的疯狂方式解析案例编号,这是新系统唯一的共同点,案例编号格式。我可以尝试解析新系统中的案例编号,然后针对这两个集运行匹配,但是有一组可能的数据,如:

DescriptionPhrase1999-A1C-12345(5 pages)
Phrase/Two2000-A1C2F-5432S(27 Pages)
DescPhraseThree2002-B2B-2345R(8 pages)

解析变得有点复杂,所以我想我会保持简单。

我将尝试单个更新语句,然后在需要时回退到clr中的正则表达式。

我会更新结果。而且,由于我已经处理了超过一半的记录,这应该有所帮助。

答案 7 :(得分:0)

尝试上面的Dan R的更新查询:

update SourceTable  
set ContainsBit = 1  
from SourceTable t1      
 join (select TargetField 
       from dbo.TargetTable t2) t2   
 on charindex(t1.SourceField, t2.TargetField) > 0

或者,如果这个的及时性很重要,这是sql 2005或更高版本,那么这将是使用带有正则表达式的SQL CLR代码的计算列的经典用法 - 不需要独立的应用程序。