2012-06-29 38 views
2

我在查詢一個表,其中包含用戶搜索的頂級結果的全文索引,然後我將通配符搜索的結果追加到結尾。如何使用TOP並有條件地忽略UNION ALL?

這裏是我的略微簡化的SQL ...

SELECT TOP(@top) * FROM  
(  
    SELECT TOP (@top) ft.[RANK], p.ProductID, p.Name FROM dbo.Product p 
    INNER JOIN FREETEXTTABLE(dbo.Product, *, @search_term) AS ft ON p.ProductID = ft.[KEY] 
    ORDER BY ft.[RANK] * p.Popularity DESC 

    UNION ALL 

    SELECT TOP (@top) 0 AS [RANK], p.ProductID, p.Name FROM dbo.Product p 
    WHERE (NOT p.ProductID IN (SELECT [KEY] FROM FREETEXTTABLE(dbo.Product, *, @search_term))) 
    AND (p.Name LIKE '%' + @search_term + '%') 
    ORDER BY p.Popularity DESC 
) AS results 

這一切工作,並一直住了一段時間。

現在,這裏是棘手的部分。我最近發現這是網站上更昂貴的查詢之一。我查看了查詢計劃,發現查詢的LIKE'%%'部分導致50-80%的成本。這真的不是什麼大驚喜,因爲通配符搜索速度很慢。麻煩的是UNION ALL的後半部分在前半部分自己返回了足夠的行時不需要運行。

有沒有辦法來 ALL執行UNION當上半年(全文搜索)返回我需要的所有行?

+0

可以存儲結果集進入臨時表,如果@@ ROWCOUNT <@top,UNION ALL與LIKE %%查詢,否則返回臨時表。也就是說,我沒有測試過,以確保該活動更有效率,這就是爲什麼這是一個評論,而不是一個答案。 –

回答

3

你可以這樣來做:

SELECT TOP (@top) ..., ft.[RANK] * p.Popularity INTO #foo ... <FT query>; 

IF @@ROWCOUNT < @top 
    INSERT #foo SELECT TOP (@top) ..., p.Popularity FROM <like query>; 

SELECT TOP (@top) ... FROM #foo ORDER BY Popularity DESC; 

它多一點的I/O,但可能是值得的偏移量。

您也可以只考慮第一個查詢返回給客戶端,並僅在該情況下,第一次是不夠的返回結果集,使應用程序足夠聰明,合併結果集。這隻有在意圖顯示ft。[RANK] * p.Popularity 之前任何結果僅由p.Popularity單獨排列時纔有效。

+0

那麼,猜猜我的評論是在正確的軌道上,嘿。很高興看到與我有限的SQL體驗所猜測的一致的答案。 –

+0

謝謝你。這是我懷疑的。我用我的搜索樣本進行了試驗,使用這種方法的讀取次數高出約10%。 CPU使用率大致相同,持續時間也大致相同。所以看起來我的原始查詢是我現在應該堅持的。不過,我會接受這個答案,因爲這絕對有幫助。 –

+0

我最後一段也可能需要進行一些測試。在第一個查詢滿足@top的情況下,它肯定會消耗更少的資源,但它需要對應用程序邏輯進行一些更改。 –

0

我不知道的方式,你可以做一個單一的語句,但你可以在第一次查詢後檢查@@rowcount,只有火第二,如果它不夠高