2009-12-15 112 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上的索引会帮助,正如其他人所说的。