2009-01-19 17 views
3

我有一堆(750K)的记录在一个表中,我必须看到他们在另一个表中。第二个表拥有数百万的记录,并且数据是这样的:TSQL“LIKE”或正则表达式?

源表
9999-A1B-1234X,与中间部分可能比三位数

目标表
DescriptionPhrase9999-A1B-1234X(9 pages)长 - 是的,括号并且这些词在现场。

目前我正在运行加载源记录的.net应用程序,然后运行并搜索类似的内容(使用tsql函数)以确定是否有任何记录。如果是,则源表格更新为肯定。如果不是,则记录保留。

该应用处理大约1000个小时的记录。当我将其作为sql server上的光标存储,我几乎得到了相同的速度。

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

回答

0

首先要确保在搜索表上有该列的索引。其次是在左侧做%LIST 而没有%符号。检查执行计划,看看你是否没有对每一行进行表扫描。

正如le dorfier正确指出的那样,如果您使用的是UDF,那就没有什么希望了。

+0

他们正在使用TSQL函数,这将使优化变得不可能。即使是表格扫描也会超过游标数量级。 – dkretz 2009-01-19 18:28:11

+0

哎呀。你是对的,没关系。 – 2009-01-19 18:28:56

3

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

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

顺便说一句,如果你使用的表大,我会决定永远不会写另一个光标。他们对于演出特别不利,特别是当你开始拍摄大小的记录时。学会用记录处理来记录集合中的记录。

+1

注意到他已经设法找到另一种让它像游标一样慢的技术。这至少是一种成就。我怀疑这是涉及UDF的搜索。 – dkretz 2009-01-19 18:33:17

5

什么做这一切在DB,而不是拉记录到您的.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次更新。

0

皮肤有很多种皮肤 - 我会认为首先知道这是一次性手术还是需要定期完成的常规任务很重要。

不知道你的问题的所有细节,如果是我,在这是一次性的(或不频繁的操作,它听起来是这样),我可能会提取出相关的领域从两个表格包括来自源表格的主键并将其作为文本文件导出到本地机器。文件大小可能会比数据库中的完整表小得多。

我会在快速机器上使用例如'C'/ C++或另一种具有原始处理能力的“轻量级”语言编写的例程在本地运行它,然后写出一个“匹配” ,然后我将重新加载到sql服务器并将其用作更新查询的基础(即更新源表,其中id从temp表中选择id)。

您可能需要花费几个小时来编写例程,但它只会在sql中看到的一小部分时间内运行。

通过您的sql语音,您可能会尝试对数百万记录表执行750,000个表扫描。

告诉我们更多关于这个问题的信息。

1

试试这个 -

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

仍然很慢,但比通过客户端应用程序的光标或路由要少得多。 – 2009-01-19 18:57:18

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) 

解析,成为复杂一点,所以我想” d保持简单。

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

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

3

使用单个更新(mbeckish的答案)需要注意的一件事是事务日志(如果查询被取消时启用回滚)将是巨大的。这将大大减慢你的查询速度。因此,以1000行或其他类似的方式处理它们可能会更好。 (750,000)中的每条记录都需要检查b(百万)中的每条记录的条件(b.field,如'%'+ a.field +'%')。这相当于超过7500亿字符串比较。不是很好。

肠道感觉“索引的东西”也不会帮助在这里。索引保持顺序,所以第一个字符决定索引中的位置,而不是你感兴趣的位置。

一是理念

为此,我居然会考虑创建一个新表,并解析长/杂乱值到的东西更好。一个例子就是去掉上一个'('开始的任何文本(假定所有的值都遵循该模式)这将简化查询条件为(b.field,如'%'+ a.field)

不过,索引对这里没有帮助,虽然因为重要的角色在最后,所以奇怪的是,在相反顺序存储两个表的字符时可能是值得的。使用

花费那么多时间看起来很浪费,但在这种情况下,一小部分的好处会产生巨大的回报(例如,几个小时的工作将比较量从750亿减少到3,750亿。如果你能得到索引,你可以减少这一千倍,这要归功于树索引earches,不只是下令表...)

第二个想法

假设你做的目标表复制到一个临时表,您可以通过删除也将匹配在1000块处理这些额外受益来自目标表的记录。 (这只有在你从目标表中删除一个有意义的数值时才值得,因此在检查完所有750,000条记录后,目标表现在[例如]它的一半大小。)

编辑:
修改第二个想法

  1. 把整个目标表中到一个临时表。

  2. 尽可能地预处理值,使字符串比较更快,甚至带来索引播放。

  3. 循环遍历源表中的每条记录。使用下面的逻辑在循环...

    DELETE目标WHERE字段LIKE '%' + @source_field + '%' IF(@@ ROW_COUNT = 0) [没有匹配] ELSE [匹配]

连续删除,使查询在每次循环加快,你只使用一个查询的数据(而不是一个以查找匹配,以及第二删除匹配)

0

尝试要么丹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代码的经典用法 - 不需要独立的应用程序。