2009-01-19 16 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代碼的經典用法 - 不需要獨立的應用程序。