2009-12-15 30 views
0

我有以下查詢...它可以工作,但運行速度非常慢。希望有人能夠給我一些提示,以提高執行時間?緩慢的mysql查詢。有小費嗎?

SELECT tb_clients.*, tb_clients_phone_fax.* 
FROM tb_clients, tb_clients_phone_fax 
WHERE tb_clients.client_id=tb_clients_phone_fax.client_id 
AND MATCH (client_company,client_description,client_keywords) AGAINST ('test') > 0 
AND CONCAT(client_address,' ',client_city,', ',client_state,' ',client_zip) LIKE '%brooklyn%' 
LIMIT 10; 

編輯:

下面是表信息:

CREATE TABLE `tb_clients` (
    `client_id` int(11) unsigned NOT NULL AUTO_INCREMENT, 
    `client_company` varchar(254) NOT NULL, 
    `client_address` varchar(254) NOT NULL, 
    `client_street` varchar(254) NOT NULL, 
    `client_city` varchar(254) NOT NULL, 
    `client_state` varchar(254) NOT NULL, 
    `client_zip` varchar(45) NOT NULL, 
    `client_email` varchar(254) NOT NULL, 
    `client_website` varchar(254) NOT NULL, 
    `client_description` text NOT NULL, 
    `client_keywords` text NOT NULL, 
    PRIMARY KEY (`client_id`) USING BTREE, 
    FULLTEXT KEY `client_company` (`client_company`,`client_description`,`client_keywords`) 
) ENGINE=MyISAM AUTO_INCREMENT=68347 DEFAULT CHARSET=latin1; 

CREATE TABLE `tb_clients_phone_fax` (
    `client_phone_fax_id` int(11) unsigned NOT NULL AUTO_INCREMENT, 
    `client_id` int(11) unsigned NOT NULL, 
    `client_phone_1` varchar(45) NOT NULL, 
    `client_phone_2` varchar(45) NOT NULL, 
    `client_phone_3` varchar(45) NOT NULL, 
    `client_fax_1` varchar(45) NOT NULL, 
    `client_fax_2` varchar(45) NOT NULL, 
    `client_fax_3` varchar(45) NOT NULL, 
    PRIMARY KEY (`client_phone_fax_id`) USING BTREE 
) ENGINE=MyISAM AUTO_INCREMENT=33944 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC; 
+0

我們可以假設'%brooklyn%'代表一個搜索參數嗎? – ChaosPandion 2009-12-15 23:31:04

+1

這將有助於顯示每個字段的數據類型以及哪些字段是索引。 – philfreo 2009-12-15 23:34:01

+0

是的,%brooklyn%'代表一個搜索參數。 – mike 2009-12-15 23:48:54

回答

2

tb_clients.client_id和tb_clients_phone_fax.client_id應該被索引。

但主要的問題似乎是兩個字符串的比較,MATCH和LIKE與CONCAT。你確定周圍沒有其他戰爭嗎?像,避免在執行LIKE語句之前連接所有地址字段?

更新:似乎tb_clients_phone_fax.client_id沒有編入索引,如果索引它會提高性能。

+0

它居然跑很快之前,我補充說: tb_clients.client_id = tb_clients_phone_fax.client_id 我只是想取出CONCAT,它仍然運行相當緩慢...... – mike 2009-12-15 23:53:20

+0

tb_clients_phone_fax.client_id沒有被索引,索引呢! – albertein 2009-12-16 00:29:29

+0

好的,我一定會在明天回去工作時試試這個最簡單的答案 – mike 2009-12-16 01:33:33

1

您應該首先確保tb_clients的索引爲client_id,而tb_clients_phone_fax的索引爲client_id

然後嘗試添加客戶端公司,客戶端描述,客戶端關鍵字索引。然而,我敢打賭,主要的減速是爲了在連接的client_address,client_city,client_state,client_zip上進行比較,所以試着找到一些其他方式來做這種比較而不用concat。你可以添加一個字段到表中保存這些項目連接的數據,然後在該字段比較嗎? (醜陋的我知道)

1

除了已經提到的索引之外,我的第一個想法是,對於你的情況一無所知,這兩個表中有多少行?其中一個只有幾千而另一個是千萬?假設您的查詢性能不是由於加入了一個非常大的數據集,那麼:

正如其他人所說的那樣,檢查您的列是否已編入索引。另外,爲什麼不全文索引你連接的列,然後在你的查詢中使用第二個MATCH()AGAINST()而不是CONCAT()和LIKE?

如何更新代碼來檢查某個zip代碼模式,然後相應地編寫查詢?或者,比方說,如果它不是郵編模式,那麼請不要去搜索那一列。

在需要搜索整個(大型)表的大容量情況下,有一件事對我很有效,就是創建一個包含整個表的串聯的列。我在該列上放置了全文索引並使用MATCH()AGAINST(),並且查詢時間非常快 - 所以根據我的經驗,全文索引可以完成工作。

現在,如果您確實有非常大的表格,那麼實時加入可能會變得無法接受。此時,您有幾個選項,但是所有這些選項都是爲了最終用戶體驗而加入後臺並存儲這些結果的變體。

+0

嗯,實際上兩個表都包含相同數量的行。像30k的東西...整個關於檢查一個郵政編碼將是很好的,但我們有不同的國家,有不同的郵政編碼的客戶:\ - 計劃檢查索引的明天... – mike 2009-12-16 01:38:37

0

我會爲表tb_clients創建一個視圖,該視圖具有包含連鎖信息的「假」列。

另外,我會索引前面提到的id列。

,那麼你會使用相同的基本查詢,替換視圖爲表和省略CONCAT(因爲它是由視圖實現爲聚合列)

我5分鐘下班,所以我無法深入細節。如果你需要代碼,例如sql等讓我知道,我會在今晚或明天晚些時候爲你安排一些東西。

0

一個非常小提示:

CONCAT(client_address,' ',client_city,', ',client_state,' ',client_zip) LIKE '%brooklyn%' 

是整個CONCAT必要嗎?你的國家或郵政編碼中是否有許多brooklyn的客戶?

(另外,你就會意識到,這將匹配像

1342布魯克林街道地址
Foobar的,MI 98765

那是故意的嗎?)

+0

好點,我甚至沒有考慮一下... – mike 2009-12-16 01:32:45

1

第一步調試慢時查詢正在運行EXPLAIN SELECT ...並查看MySQL實際正在做什麼,而不是猜測。但是,是的,它看起來像tb_clients_phone_fax.client_id上的索引會幫助,正如其他人所說的。