2017-05-18 59 views
0

我有2个表, '[项目]与区[name]为nvarchar(255) '[交易]与现场[SHORT_DESCRIPTION]为nvarchar(3999)一个大 '像' 匹配查询

而且我需要这样做:

Select [Transaction].id, [Item].id 
From [Transaction] inner join [Item] 
on [Transaction].[short_description] like ('%' + [Item].[name] + '%') 

上述工作如果局限于几件作品,未经过滤的却是只是在看20分钟,我取消。

我在[name]上有一个NC索引,但由于它的长度,我无法编制索引[short_description]。

[Transaction] has 320,000 rows 
[Items] has 42,000. 

这是13,860,000,000个组合。

有没有更好的方法来执行此查询? 我用全文戳了一下,但我其实并不那么熟悉,答案并没有跳出去。

任何意见赞赏!

+0

您正在加入通配符。没有办法做得更快。它必须比较每一个单项与每一笔交易。 –

+0

这可能是非规范化有意义的情况。您可以创建一个单独的表来交叉引用项目名称和事务简短描述。两个表上的触发器都会使交叉引用保持最新。如果您可以容忍一些陈旧的数据,您可以放弃触发器并安排工作以在适当的时间刷新交叉引用。 – HABO

回答

3

使用通配符(%或_)开始比较字符串将永远不会使用索引,并且通常会对性能造成灾难性影响。您的查询将需要扫描索引而不是通过查找索引,因此索引不会有帮助。

理想情况下,您应该有第三个表,允许基于ID的Transaction和Item之间的多对多关系。这里的设计是问题。

+0

即使从索引扫描中也可以获得一些好处。索引扫描通常比表扫描需要更少的I/O。索引宽度相对于行宽度越小,益处就越大。 – HABO

+0

我更新了我的答案,以便更加精确,但除非您正在查看过滤的索引,否则您可能正在查看表扫描或聚簇索引扫描,所以同样重要。 OP提出的问题的根源仍然是设计。加入文字的某些中间部分不可扩展。 –

0

经过一番探索后,我利用了一些全文本功能。

sp_fulltext_keymappings 给我我的事务表ID,与FT docID的 (我发现 'DOC'=文本字段)

sys.dm_fts_index_keywords_by_document 一起给我FT documentId沿与其中的单个关键字

一旦我有了,其余的很简单。 虽然,我不得不查看术语'关键字'多一点...似乎这个定义可以是可变的。

这只适用于我搜索的文本没有空格。 我相信你可以调整FTI配置以与其他场景一起工作......但我无法承诺。 我需要更多地看全文。

我目前的'测试'代码如下。

CREATE TABLE #keyMap 
    ( 
     docid INT PRIMARY KEY , 
     [key] varchar(32) NOT NULL 
    ); 
DECLARE @db_id int = db_id(N'<database name>'); 
DECLARE @table_id int = OBJECT_ID(N'Transactions'); 

INSERT INTO #keyMap 
EXEC sp_fulltext_keymappings @table_id; 

select km.[key] as transaction_id, i.[id] as item_id 
from  
    sys.dm_fts_index_keywords_by_document (@db_id, @table_id) kbd 
    INNER JOIN 
    #keyMap km ON km.[docid]=kbd.document_id 
    inner join [items] i 
    on kdb.[display_term] = i.name 
    ; 

我的代码实际版本包括将数据插入到最终表中。执行时间在30秒内到达,这为我现在的需求服务。