2012-10-15 63 views
3

我試圖在我的數據庫中的字段中搜索相同的文本以查找livesearch框。使用Postgres在多個字段中搜索一個詞條

SELECT DISTINCT u.id, u.username FROM 
users AS u, user_invoice AS ui, user_roles AS ur, roles AS r WHERE 
u.id = ur.user_id AND 
ur.role_id = r.id AND 
r.name = 'teacher' AND 
(
    ui.user_id = u.id AND 
    CAST(ui.invoice AS TEXT) = 'searchterm' 
) 

此查詢將搜索發票表並正確且快速地返回結果。

SELECT DISTINCT u.id, u.username FROM 
users AS u, user_invoice AS ui, user_roles AS ur, roles AS r WHERE 
u.id = ur.user_id AND 
ur.role_id = r.id AND 
r.name = 'teacher' AND 
(u.username like '%searchterm%') 

此查詢會搜索匹配的用戶名,並且返回速度也非常快。

但是,當我將二者結合起來是這樣的:

SELECT DISTINCT u.id, u.username FROM 
users AS u, user_invoice AS ui, user_roles AS ur, roles AS r WHERE 
u.id = ur.user_id AND 
ur.role_id = r.id AND 
r.name = 'teacher' AND 
(
    u.username like '%searchterm%' OR 
    (
     ui.user_id = u.id AND 
     CAST(ui.invoice AS TEXT) = 'searchterm' 
    ) 
) 

它返回正確的結果,但需要差不多一分鐘這樣做。我究竟做錯了什麼?

編輯:我查詢的解釋:

第一: http://explain.depesz.com/s/PvS

二: http://explain.depesz.com/s/D5c

組合: http://explain.depesz.com/s/Dhf


編輯的錯誤在複製投行。

+0

PostgreSQL版本?請同時顯示'解析分析'輸出;粘貼到explain.depesz.com並鏈接到這裏。 –

+0

如果您將查詢重寫爲JOIN語法,您可能會發現自己。 – wildplasser

+0

我必須同意wildplasser--使用'FROM INNER JOIN ON(condition)'而不是'FROM a,b WHERE(condition)'來理解發生了什麼很容易。另外,三人中的第二個如何產生明智的結果?你有一個來自不受限制的加入'ui'的笛卡爾產品。 –

回答

0

空操作(轉化成JOIN語法)(不是前面回答!):

SELECT DISTINCT u.id, u.username 
FROM 
users AS u 
JOIN user_invoice AS ui ON u.username like '%searchterm%' 
         OR (ui.user_id = u.id AND ui.invoice = CAST('searchterm' AS INTEGER)) 
JOIN user_roles AS ur ON u.id = ur.user_id 
JOIN roles AS r ON ur.role_id = r.id 
WHERE r.name = 'teacher' 
    ; 

CAST('searchterm' AS INTEGER))是沒有意義的我。雙引號?參數?

+0

searchterm可以是字母數字,而字段發票是一個整數。它沒有演員就拋出一個錯誤,所以我把它留在那裏。 – Fillmore

+0

我的錯誤,我複製了錯誤的代碼。我實際上是CAST(ui.invoice AS TEXT)='searchterm' – Fillmore

1

下面是我在主應用程序中解決這個問題的方法。

我有一個主要實體,我希望用戶能夠搜索。叫它customer。該實體在1:n contact(用於電話,電子郵件等)表中具有關聯的詳細記錄。

我定義視圖,customer_quicksearch,計算一個快速搜索鍵 - 包含contact記錄的串聯與一些直接customer場沿一個客戶text場。

我已將觸發器添加到customercontactcustomer_summary表中。當一行插入customer時,customer觸發器會向customer_summary添加記錄,並在刪除customer記錄時刪除該行。他們通過SELECT更新customer_summary來自`customer_quicksearch'的更新的快速搜索關鍵字。我可以使用SQL函數代替視圖,但發現視圖更加實用和快捷。通過查看,可以快速計算所有客戶的快速搜索鍵,例如在批量插入或更新後。

CREATE VIEW customer_quicksearch AS 
SELECT 
     customer.id AS customer_id, array_to_string(ARRAY[ 
       customer.code, 
       customer.name, 
       string_agg(array_to_string(ARRAY[ 
         contact.email::text,contact.altemail::text, contact.mobile_phone, contact.work_phone, contact.home_phone, contact.fax 
       ],'|'),'|') 
     ], '|') AS quicksearch_key 
FROM customer 
LEFT OUTER JOIN contact ON (customer.id = contact.customer_id) 
GROUP BY customer.id; 

和觸發器之一:

CREATE OR REPLACE FUNCTION customer_summary_update_for_contact() RETURNS trigger AS $$ 
DECLARE 
    _customer_id integer; 
BEGIN 
    -- When a contact is added/removed/changed we have to regenerate the customer search key 
    IF tg_op = 'INSERT' OR tg_op = 'UPDATE' THEN 
     _customer_id = NEW.customer_id; 
    ELSE 
     _customer_id = OLD.customer_id; 
    END IF; 
    UPDATE customer_summary 
    SET quicksearch_key = (SELECT quicksearch_key FROM customer_quicksearch WHERE customer_id = _customer_id) 
    WHERE customer_id = _customer_id; 
    RETURN NULL; 
END; 
$$ 
LANGUAGE 'plpgsql' 
SET search_path = 'public'; 

CREATE TRIGGER customer_summary_update_for_contact_trg AFTER INSERT OR UPDATE OR DELETE ON contact 
FOR EACH ROW EXECUTE PROCEDURE customer_summary_update_for_contact(); 

您還需要在customer觸發處理insertupdate和客戶的delete,保持customer_summary記錄該客戶適當。

customer_summary表包含的記錄,其中包括一個quicksearch_key這是字段的管道串聯,如:

'1800MA|1800 MAKE IT BUILDERS|[email protected]|1234 5678|0499 999 999' 
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^ 
[from customer record]  [from 1st contact record]    [from another contact record] 

這是搜索一個簡單的LIKE模式。如果我在進行前綴搜索,我可以在其上添加一個text_pattern_ops索引以提高性能,但由於我大多在做沒有左側或右側錨點的搜索 - LIKE '%search%' - 沒有任何好處。

+0

您可以使用新的trigram索引類型來使'like'%search%'使用索引 –

+0

@a_horse_with_no_name哦,好點。它在小數據集規模上足夠快,以至於沒有必要擔心優化的方式,但每一點都有幫助。 –