2017-05-18 80 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秒內到達,這爲我現在的需求服務。