2013-05-08 75 views
9

我對上的SQL Server 2008R2一個簡單的表自由文本目錄:結合自由文本搜索與另一個條件是

CREATE FULLTEXT CATALOG customer_catalog; 
CREATE FULLTEXT INDEX ON customer 
( 
    name1 
) 
    KEY INDEX customer_pk 
    ON customer_catalog; 
ALTER FULLTEXT INDEX ON customer START UPDATE POPULATION; 

如果我幾乎立即執行以下三個查詢的前兩回,而最後一個需要14秒左右在桌子上有100,000個記錄:

SELECT 
     customer_id 
    FROM 
     customer 
    WHERE 
     CONTAINS(customer.*, 'nomatch'); 

SELECT 
     customer_id 
    FROM 
     customer 
    WHERE 
     customer.customer_id = 0; 

SELECT 
     customer_id 
    FROM 
     customer 
    WHERE 
     CONTAINS(customer.*, 'nomatch') 
      OR customer.customer_id = 0; 

這裏是queryplans:

enter image description here

爲什麼第三個查詢慢得多?我可以做任何事情來改善它,或者我需要拆分查詢嗎?

+0

通常,將'CONTAINS'查詢重寫爲'CONTAINSTABLE'會將此類問題排序。 [例如在這個答案](http://stackoverflow.com/questions/2906812/adding-more-or-searches-with-contains-brings-query-to-crawl/2907331#2907331) – 2013-05-11 22:09:58

+1

根據你的2008R2 SP版本,您的問題可能與下面的MS Connect問題有關:http://connect.microsoft.com/SQLServer/feedback/details/520653/full-text-performance-with-mixed-queries – MicSim 2013-05-17 14:16:13

+0

@MicSim:如果您使成爲答案,我會接受它。雖然其他答案提供了很好的解決方法,但您的看起來像是真正的答案。謝謝! – 2013-05-17 17:36:21

回答

2

根據您的MS SQL 2008 R2服務包版本,您的問題可能與以下Microsoft Connect問題有關:Full-text performance with "mixed queries"

根據MS Connect條目,在爲SQL Server 2008 R2安裝最新的累積更新包後,問題應該消失。

3

很難說爲什麼,但似乎SQL Server正在選擇一個效率低下的查詢計劃。下面是一些建議:

更新表上的統計信息:

UPDATE STATISTICS dbo.customer 

一旦統計數據是最新的,你可以再次嘗試你的查詢,看看是否有改善。

還有一點是,對於組合的OR語句,SQL Server正在使用索引掃描,而不是查找。你可以嘗試FORCESEEK提示,看看是否有差別:其他

SELECT customer_id 
FROM customer WITH (FORCESEEK) 
WHERE CONTAINS(customer.*, 'nomatch') 
OR customer.customer_id = 0; 

一種選擇,正如你所說,是分裂的語句。下面UNION執行的一樣好,你的前兩個語句組合:

SELECT customer_id FROM customer 
WHERE CONTAINS(customer.*, 'nomatch') 

UNION 

SELECT customer_id FROM customer 
WHERE customer.customer_id = 0 

更新 - 上面的查詢變爲UNION而不是UNION ALL

由於@PondLife在評論中指出,我的意思是在上述查詢中執行UNION而不是UNION ALL。想過之後,我也嘗試了UNION ALL,它似乎更快。這是假設你不關心重複的ID:

SELECT customer_id FROM customer 
WHERE CONTAINS(customer.*, 'nomatch') 

UNION ALL 

SELECT customer_id FROM customer 
WHERE customer.customer_id = 0 
+0

我認爲你的意思是'UNION',而不是'UNION ALL'(在這個特定情況下),否則包含'nomatch'*和*的ID 0的行將在結果集中出現兩次而不是一次。 – Pondlife 2013-05-10 20:43:49

+0

@Pondlife - 你是對的,我會更新。謝謝。 – 2013-05-10 20:46:54

3

的「OR」 logicial條件往往使查詢的運行速度很慢:/ 通常情況下,最好的選擇是使用UNION(ALL)。

在你的情況,我很好奇你做的

SELECT 
    customer_id 
FROM 
    customer 
WHERE 
    customer.customer_id = 0; 

它只會導致零的列表(可能爲空)的使用。 計數(!)有多少客戶有一個id = 0? 是否要檢查是否有客戶的ID爲0?

如果不是計數爲零,但要知道,如果他們有,那麼這個查詢應該是有效的:

SELECT 
    customer_id 
FROM 
    customer 
WHERE 
    CONTAINS(customer.*, 'nomatch') 
    AND customer.customer_id <> 0 
UNION ALL 
SELECT TOP(1) 
    0 
FROM 
    customer 
WHERE 
    customer.customer_id = 0 

否則高效的查詢是這樣的一個:

SELECT 
    customer_id 
FROM 
    customer 
WHERE 
    CONTAINS(customer.*, 'nomatch') 
    AND customer.customer_id <> 0 
UNION ALL 
SELECT 
    0 
FROM 
    customer 
WHERE 
    customer.customer_id = 0 

(我剛剛刪除了TOP子句)

+0

'customer_id = 0'只是爲了展示一個簡單的例子。實際的查詢是兩個包含CONTAINS(table1。*)或CONTAINS(table2。*)的表的連接。但是我意識到只要在id列上查詢就可以重現問題,所以我認爲這將是一個更簡單的例子。 – 2013-05-13 10:41:27

+0

條件不重要,使用我的第二個查詢。從使用全文索引的部分開始,並對其進行過濾以排除第二部分(在本例中使用customer.customer_id <> 0),然後在第二部分創建一個全部聯合。 – Serge 2013-05-15 07:57:58

相關問題