使用两个索引列时,mySQL查询速度慢

时间:2013-04-19 09:29:23

标签: mysql select indexing

我有一个包含大约200万行的mySQL表(myISAM) - 名称,地址,公司数据。名字和姓氏分别保存在列中,因此我还有第二个表(由第一个表的主键链接),它包含一个全名列。

第一个表中的名字,姓氏和公司名称(以及其他名称)都被编入索引,辅助表中的全名列也是如此。

以此查询为出发点:

SELECT * FROM table_a INNER JOIN table_b ON table_a.ID = table_b.ID WHERE....

在名称列上搜索完全匹配甚至类似之后的工作在几毫秒内完成:

....table_a.first_name = 'Fred'
....table_a.surname = 'Bloggs'
....table_b.fullname = 'Fred Bloggs'
....table_a.first_name LIKE 'Mike%'

只是一些例子。

将公司名称也放在那里......查询突然需要15到20秒:

....table_a.first_name = 'Fred' OR table_a.company_name = 'Widgets Inc'

例如

两个字段都已编入索引,这是一个完全匹配....为什么添加第二个索引搜索列会减慢这么多?我错过了关于桌子设计的一些事情吗?

示例如下 - 还有一些其他表已加入,但我不确定这些是否会影响性能: 仅返回名称的查询示例,返回0.0123秒:

SELECT SQL_CALC_FOUND_ROWS 
    webmaster.dupe_master_id AS webmaster_id, 
    webmaster.first_name, 
    webmaster.family_name, 
    webmaster.job_title, 
    webmaster.company_name, 
    webmaster.address_1, 
    webmaster.address_2, 
    webmaster.town_city, 
    webmaster.state_county, 
    webmaster.post_code, 
    webmaster.email, 
    webmaster.ignored, 
    countries.country_name, 
    GROUP_CONCAT(DISTINCT titles.code ORDER BY code ASC) AS sub_string, 
    '' AS expo_string 
FROM 
    (`webmaster`) 
    LEFT JOIN `countries` ON `countries`.`country_id` = `webmaster`.`country_id` 
    LEFT JOIN `red_subscriptions` ON `red_subscriptions`.`webmaster_id` = `webmaster`.`webmaster_id` AND red_subscriptions.subscription_status_id = 2 
    LEFT JOIN `titles` ON `titles`.`title_id` = `red_subscriptions`.`title_id` 
    LEFT JOIN `webmaster_tags` ON `webmaster_tags`.`webmaster_id` = `webmaster`.`webmaster_id` 
    LEFT JOIN `tags` ON `tags`.`tag_id` = `webmaster_tags`.`tag_id` 
    INNER JOIN `webmaster_search_data` ON `webmaster`.`webmaster_id` = `webmaster_search_data`.`webmaster_id` 
WHERE 
    (full_name = '<name>') 
GROUP BY 
    `webmaster`.`dupe_master_id` 
LIMIT 50

添加公司名称(也已编入索引),查询时间可以通过屋顶:

SELECT SQL_CALC_FOUND_ROWS 
    webmaster.dupe_master_id AS webmaster_id, 
    webmaster.first_name, 
    webmaster.family_name, 
    webmaster.job_title, 
    webmaster.company_name, 
    webmaster.address_1, 
    webmaster.address_2, 
    webmaster.town_city, 
    webmaster.state_county, 
    webmaster.post_code, 
    webmaster.email, 
    webmaster.ignored, 
    countries.country_name, 
    GROUP_CONCAT(DISTINCT titles.code ORDER BY code ASC) AS sub_string, 
    '' AS expo_string 
FROM 
    (`webmaster`) 
    LEFT JOIN `countries` ON `countries`.`country_id` = `webmaster`.`country_id` 
    LEFT JOIN `red_subscriptions` ON `red_subscriptions`.`webmaster_id` = `webmaster`.`webmaster_id` AND red_subscriptions.subscription_status_id = 2 
    LEFT JOIN `titles` ON `titles`.`title_id` = `red_subscriptions`.`title_id` 
    LEFT JOIN `webmaster_tags` ON `webmaster_tags`.`webmaster_id` = `webmaster`.`webmaster_id` 
    LEFT JOIN `tags` ON `tags`.`tag_id` = `webmaster_tags`.`tag_id` 
    INNER JOIN `webmaster_search_data` ON `webmaster`.`webmaster_id` = `webmaster_search_data`.`webmaster_id` 
WHERE 
    (full_name = '<name>' OR company_name '<name>') 
GROUP BY 
    `webmaster`.`dupe_master_id` 
LIMIT 50

仅对full_name进行解析:

id select_type表类型possible_keys键key_len ref rows Extra 1 SIMPLE webmaster_search_data ref webmaster_id,full_name full_name 302 const 94使用where;使用临时;使用filesort 1 SIMPLE网站管理员eq_ref PRIMARY PRIMARY 4 webmaster_search_data.webmaster_id 1
1 SIMPLE国家eq_ref PRIMARY PRIMARY 2 webmaster.country_id 1
1 SIMPLE red_subscriptions ref webmaster_id,subscription_status_id webmaster_id 4 webmaster_search_data.webmaster_id 1
1 SIMPLE titles eq_ref PRIMARY PRIMARY 2 red_subscriptions.title_id 1
1 SIMPLE webmaster_tags参考webmaster_id webmaster_id 4 webmaster_search_data.webmaster_id 5
1 SIMPLE标签eq_ref PRIMARY PRIMARY 2 webmaster_tags.tag_id 1使用索引

解释何时添加company_name:

1个SIMPLE网站管理员索引PRIMARY,company_name dupe_master_id 4 NULL 2072015使用filesort 1 SIMPLE国家eq_ref PRIMARY PRIMARY 2 webmaster.country_id 1
1 SIMPLE red_subscriptions ref webmaster_id,subscription_status_id webmaster_id 4 webmaster.webmaster_id 1
1 SIMPLE titles eq_ref PRIMARY PRIMARY 2 red_subscriptions.title_id 1
1 SIMPLE webmaster_tags参考webmaster_id webmaster_id 4 webmaster.webmaster_id 5
1 SIMPLE标签eq_ref PRIMARY PRIMARY 2 webmaster_tags.tag_id 1使用索引 1 SIMPLE webmaster_search_data eq_ref webmaster_id,full_name webmaster_id 4 webmaster.webmaster_id 1使用地点

1 个答案:

答案 0 :(得分:0)

MySQL不能同时使用两个索引。当您输入公司名称时,MySQL不能再使用Firstname,Lastname上的索引,因为现在需要检查更多列才能获得准确的结果。

可能正在进行全表扫描。

您可以通过联盟来分割您的查询,这样您就可以将这两个列与索引一起使用。

SELECT * FROM
( SELECT * FROM table_a 
  INNER JOIN table_b ON table_a.ID = table_b.ID 
  WHERE table_a.first_name = 'Fred' 
  UNION
  SELECT * FROM table_a 
  INNER JOIN table_b ON table_a.ID = table_b.ID
  WHERE table_a.company_name = 'Widgets Inc'
) sub;

应分别评估每个查询并使用适当的索引。 UNION将照顾双打,所以你最终会得到相同的结果。