【发布时间】:2019-06-17 21:32:45
【问题描述】:
我有两张桌子:
表 1:100 行
表 2:1000 万行
例子:
表一:tb100
create table tb100
(
name varchar(50)
);
insert into tb100 values('Mak John'),('Will Smith'),('Luke W')......100 rows.
表2:tb10mil
create table tb10mil
(
name varchar(50)
);
insert into tb10mil values('John A Mak'),('K Smith Will'),('James Henry')......10 millions rows.
create nonclustered index nci_tb10mil_name on tb10mil(name);
注意:如果另一个表中存在任何 WORD(John,Smith,Will),我想匹配两个表之间的名称。例如 John 出现在 John A Mark 中。
我的尝试:
首先,我创建了用于将name 的tb100 拆分为行的用户定义函数。
函数:udf_Split
CREATE FUNCTION [dbo].[udf_Split]
(
@InputString VARCHAR(8000),
@Delimiter VARCHAR(50)
)
RETURNS @Items TABLE (ID INTEGER IDENTITY(1,1), Item VARCHAR(8000))
AS
BEGIN
IF @Delimiter = ' '
BEGIN
SET @Delimiter = ','
SET @InputString = REPLACE(@InputString, ' ', @Delimiter)
END
IF (@Delimiter IS NULL OR @Delimiter = '')
SET @Delimiter = ','
DECLARE @Item VARCHAR(8000)
DECLARE @ItemList VARCHAR(8000)
DECLARE @DelimIndex INT
SET @ItemList = @InputString
SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
WHILE (@DelimIndex != 0)
BEGIN
SET @Item = SUBSTRING(@ItemList, 0, @DelimIndex)
INSERT INTO @Items VALUES (@Item)
SET @ItemList = SUBSTRING(@ItemList, @DelimIndex+1, LEN(@ItemList)-@DelimIndex)
SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
END
IF @Item IS NOT NULL
BEGIN
SET @Item = @ItemList
INSERT INTO @Items VALUES (@Item)
END
ELSE INSERT INTO @Items VALUES (@InputString)
RETURN
END
然后我写了以下查询:
;with splitdata as
(
select f.item as data
from tb100 t
cross apply dbo.udf_split(t.name,' ') f
)
select t2.name
from tb10mil t2
inner join splitdata c on charindex(c.data,t2.name)>0
group by t2.name
上述查询的执行时间超过 20 分钟。
【问题讨论】:
-
你为什么要为你的分离器使用
WHILE循环?有很多数据集解决方案会快得多。我建议使用 XML 拆分器或 delimitedsplit8k(如果它不是nvarchar(MAX))。该拆分器很可能是您的(第一个)问题.. -
首先,SQL 不是一种文本处理语言,所以你不能指望良好的文本分割性能。其次,没有索引就无法提高性能,并且该功能无法使用索引。最后,SQL Server 在 SSIS 中已经具备全文搜索功能以及模糊匹配和查找功能。如果您想在加载 10M 行时模糊匹配名称,请在 SSIS 中使用模糊查找运算符
-
如果您想将销售表与一组客户记录按名称进行匹配,请在加载数据时执行此操作,并且仅在目标表中存储实际 ID。每次要加入表时,不要尝试重复模糊查找。无论您使用哪种技术,模糊匹配总是比连接两个索引列慢
-
如果这个查询会被频繁使用,那么最好在主表上维护一个 AFTER 触发器的映射表,并将拆分的数据作为表列值保存。然后可以在这个新的映射表上建立连接
-
使用 SQL FOR XML PATH 方法分割字符串,下面的 UDF 函数可以替代kodyaz.com/articles/…
标签: sql-server tsql sql-server-2008-r2 database-performance