Mysql 表索引良好,但执行查询需要很长时间?
我们的一个查询是扫描整个表,它占用了所有的时间 15分钟,这对我们的应用程序性能产生了影响。桌子 有适当的索引,但它正在扫描完整的表。如何 重写或者有没有最好的索引方法 查询:Mysql 表索引良好,但执行查询需要很长时间?,mysql,sql,database-performance,Mysql,Sql,Database Performance,我们的一个查询是扫描整个表,它占用了所有的时间 15分钟,这对我们的应用程序性能产生了影响。桌子 有适当的索引,但它正在扫描完整的表。如何 重写或者有没有最好的索引方法 查询: select count(u.user_id) from iflora_user_newsletter_map unm, users u , addresses a where unm.user_id=u.user_id and unm.newsletter_
select count(u.user_id)
from iflora_user_newsletter_map unm,
users u ,
addresses a
where unm.user_id=u.user_id
and unm.newsletter_id=1
and unm.active=1
and u.user_id=a.user_id
and a.type='billing';\
解释计划:
+----+-------------+-------+------+------------------+----------+---------+----------------------+---------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+------------------+----------+---------+----------------------+---------+--------------------------+
| 1 | SIMPLE | unm | ref | idx_2243,idx_747 | idx_2243 | 4 | const | 2960628 | Using where |
| 1 | SIMPLE | u | ref | idx_747 | idx_747 | 5 | shopcart.unm.user_id | 1 | Using where; Using index |
| 1 | SIMPLE | a | ref | idx_747 | idx_747 | 4 | shopcart.unm.user_id | 1 | Using where |
+----+-------------+-------+------+------------------+----------+---------+----------------------+---------+--------------------------+
3 rows in set (0.05 sec)
表结构:
mysql> show create table iflora_user_newsletter_map\G
*************************** 1. row ***************************
Table: iflora_user_newsletter_map
Create Table: CREATE TABLE `iflora_user_newsletter_map` (
`row_mod` datetime DEFAULT NULL,
`row_create` datetime DEFAULT NULL,
`user_id` int(11) NOT NULL,
`newsletter_id` int(11) NOT NULL,
`active` int(11) DEFAULT NULL,
`date_subscribed` datetime DEFAULT NULL,
`date_unsubscribed` datetime DEFAULT NULL,
`email_preference` int(11) DEFAULT NULL,
`mail_preference` int(11) DEFAULT NULL,
`sms_preference` int(11) DEFAULT NULL,
`phone_preference` int(11) DEFAULT NULL,
UNIQUE KEY `idx_2243` (`newsletter_id`,`user_id`),
KEY `idx_1571` (`date_subscribed`),
KEY `idx_1798` (`date_unsubscribed`),
KEY `idx_747` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin
1 row in set (0.00 sec)
mysql> show create table users\G
*************************** 1. row ***************************
Table: users
Create Table: CREATE TABLE `users` (
`row_mod` datetime DEFAULT NULL,
`row_create` datetime DEFAULT NULL,
`user_id` int(11) DEFAULT NULL,
`name` varchar(50) COLLATE latin1_bin DEFAULT NULL,
`password` varchar(255) COLLATE latin1_bin DEFAULT NULL,
`salt` varchar(12) COLLATE latin1_bin DEFAULT NULL,
`last_visit` int(11) DEFAULT NULL,
`member_since` int(11) DEFAULT NULL,
`email` varchar(100) COLLATE latin1_bin DEFAULT NULL,
`active` int(11) DEFAULT NULL,
`transient` int(11) DEFAULT NULL,
`fname` varchar(50) COLLATE latin1_bin DEFAULT NULL,
`lname` varchar(50) COLLATE latin1_bin DEFAULT NULL,
`default_address_id` decimal(12,0) DEFAULT NULL,
`opt_in_email` char(1) COLLATE latin1_bin DEFAULT NULL,
`opt_in_email2` char(1) COLLATE latin1_bin DEFAULT NULL,
`opt_in_email3` char(1) COLLATE latin1_bin DEFAULT NULL,
`email_promotions` char(1) COLLATE latin1_bin DEFAULT NULL,
`textonly_email` char(1) COLLATE latin1_bin DEFAULT NULL,
`website_id` int(11) DEFAULT NULL,
`express_checkout` int(11) DEFAULT NULL,
`webstore_id` int(11) DEFAULT NULL,
UNIQUE KEY `idx_747` (`user_id`),
KEY `idx_417` (`name`),
KEY `idx_delete_transient` (`transient`,`last_visit`),
KEY `users_n1` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin
1 row in set (0.00 sec)
mysql> show create table addresses\G
*************************** 1. row ***************************
Table: addresses
Create Table: CREATE TABLE `addresses` (
`row_mod` datetime DEFAULT NULL,
`row_create` datetime DEFAULT NULL,
`address_id` decimal(12,0) NOT NULL,
`user_id` int(11) NOT NULL,
`name` varchar(30) COLLATE latin1_bin DEFAULT NULL,
`type` varchar(20) COLLATE latin1_bin DEFAULT NULL,
`fname` varchar(50) COLLATE latin1_bin DEFAULT NULL,
`lname` varchar(50) COLLATE latin1_bin DEFAULT NULL,
`company` varchar(100) COLLATE latin1_bin DEFAULT NULL,
`email` varchar(100) COLLATE latin1_bin DEFAULT NULL,
`street_address` varchar(100) COLLATE latin1_bin DEFAULT NULL,
`address2` varchar(100) COLLATE latin1_bin DEFAULT NULL,
`city` varchar(30) COLLATE latin1_bin DEFAULT NULL,
`state` varchar(40) COLLATE latin1_bin DEFAULT NULL,
`zip` varchar(10) COLLATE latin1_bin DEFAULT NULL,
`country` varchar(20) COLLATE latin1_bin DEFAULT NULL,
`day_phone` varchar(20) COLLATE latin1_bin DEFAULT NULL,
`day_phone_ext` varchar(10) COLLATE latin1_bin DEFAULT NULL,
`evening_phone` varchar(20) COLLATE latin1_bin DEFAULT NULL,
`mobile_phone` varchar(20) COLLATE latin1_bin DEFAULT NULL,
`fax` varchar(15) COLLATE latin1_bin DEFAULT NULL,
`location_name` varchar(40) COLLATE latin1_bin DEFAULT NULL,
`personal_notes` varchar(100) COLLATE latin1_bin DEFAULT NULL,
`complete_flag` varchar(1) COLLATE latin1_bin DEFAULT 'N',
`credit_card_number` varchar(20) COLLATE latin1_bin DEFAULT NULL,
`credit_card_type` varchar(10) COLLATE latin1_bin DEFAULT NULL,
`credit_card_exp_month` int(11) DEFAULT NULL,
`credit_card_exp_year` int(11) DEFAULT NULL,
`birthday` datetime DEFAULT NULL,
`title` varchar(10) COLLATE latin1_bin DEFAULT NULL,
`street_address2` varchar(100) COLLATE latin1_bin DEFAULT NULL,
`district` varchar(30) COLLATE latin1_bin DEFAULT NULL,
`verified` int(11) DEFAULT NULL,
`email_type` varchar(1) COLLATE latin1_bin DEFAULT NULL,
`location_type` varchar(20) COLLATE latin1_bin DEFAULT NULL,
`birth_day` varchar(4) COLLATE latin1_bin DEFAULT NULL,
`birth_month` varchar(4) COLLATE latin1_bin DEFAULT NULL,
`birth_year` varchar(4) COLLATE latin1_bin DEFAULT NULL,
`skip_queries` int(11) DEFAULT NULL,
`has_qas_results` int(11) DEFAULT NULL,
`qas_queried` int(11) DEFAULT NULL,
`debit_card_issue_number` varchar(6) COLLATE latin1_bin DEFAULT NULL,
`credit_card_start_year` varchar(4) COLLATE latin1_bin DEFAULT NULL,
`credit_card_start_month` varchar(4) COLLATE latin1_bin DEFAULT NULL,
`in_the_name_of` varchar(30) COLLATE latin1_bin DEFAULT NULL,
`parameters` varchar(1024) COLLATE latin1_bin DEFAULT NULL,
UNIQUE KEY `idx_1042` (`address_id`),
KEY `idx_747` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin
1 row in set (0.00 sec)
@莫里洛
下面是添加索引后的解释
在iflora用户通讯地图上创建索引idx_748(用户id,通讯id,活动)
说明计划
mysql> explain select count(u.user_id) from iflora_user_newsletter_map unm, users u , addresses a where unm.user_id=u.user_id and unm.newsletter_id=1 and unm.active=1 and u.user_id=a.user_id and a.type='billing';
+----+-------------+-------+--------+-----------------------------------+----------+---------+--------------------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-----------------------------------+----------+---------+--------------------------+------+-------------+
| 1 | SIMPLE | u | index | idx_747 | idx_747 | 5 | NULL | 2575 | Using index |
| 1 | SIMPLE | a | ref | idx_747,idx_ads | idx_747 | 4 | shopcart.u.user_id | 1 | Using where |
| 1 | SIMPLE | unm | eq_ref | idx_2243,idx_news,idx_747,idx_748 | idx_2243 | 8 | const,shopcart.u.user_id | 1 | Using where |
+----+-------------+-------+--------+-----------------------------------+----------+---------+--------------------------+------+-------------+
3 rows in set (0.00 sec)
Explain Plan use force index
mysql> explain select count(u.user_id) from iflora_user_newsletter_map unm, users u , addresses a where unm.user_id=u.user_id and unm.newsletter_id=1 and unm.active=1 and u.user_id=a.user_id and a.type='billing';
+----+-------------+-------+--------+-----------------------------------+----------+---------+--------------------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-----------------------------------+----------+---------+--------------------------+------+-------------+
| 1 | SIMPLE | u | index | idx_747 | idx_747 | 5 | NULL | 2575 | Using index |
| 1 | SIMPLE | a | ref | idx_747,idx_ads | idx_747 | 4 | shopcart.u.user_id | 1 | Using where |
| 1 | SIMPLE | unm | eq_ref | idx_2243,idx_news,idx_747,idx_748 | idx_2243 | 8 | const,shopcart.u.user_id | 1 | Using where |
+----+-------------+-------+--------+-----------------------------------+----------+---------+--------------------------+------+-------------+
3 rows in set (0.00 sec)
由于条件“unm.newsletter_id=1和unm.active=1”,select正在扫描所有行:这些字段没有索引,因此引擎必须扫描所有行。 将这些字段也包括在索引“user_id”中以解决问题。 我建议更改:
按键
idx\U 747
(用户id
)到
键
idx\U 747
(user\u id
,newsletter\u id
,active
)由于条件“unm.newsletter\u id=1和unm.active=1”,选择正在扫描所有行:这些字段没有索引,因此,引擎必须扫描所有行。
将这些字段也包括在索引“user_id”中以解决问题。
我建议更改:按键
idx\U 747
(用户id
)到
键
idx\U 747
(user\u id
,newsletter\u id
,active
)这是用正确的联接语法编写的查询:
select count(u.user_id)
from iflora_user_newsletter_map unm join
users u
on unm.user_id = u.user_id join
addresses a
on u.user_id = a.user_id
where unm.newsletter_id = 1 and unm.active = 1 and a.type = 'billing';
此查询可能受益于以下索引:
addresses(user_id, type)
iflora_user_newsletter_map(newsletter_id, active, user_id)
或:
我在表中的索引中没有看到
where
子句中的列。哪一个更好取决于每个表中有多少数据用于索引。较大的表似乎是unm
,因此我将首先尝试第一组索引。这是使用正确的联接语法编写的查询:
select count(u.user_id)
from iflora_user_newsletter_map unm join
users u
on unm.user_id = u.user_id join
addresses a
on u.user_id = a.user_id
where unm.newsletter_id = 1 and unm.active = 1 and a.type = 'billing';
此查询可能受益于以下索引:
addresses(user_id, type)
iflora_user_newsletter_map(newsletter_id, active, user_id)
或:
我在表中的索引中没有看到
where
子句中的列。哪一个更好取决于每个表中有多少数据用于索引。较大的表似乎是unm
,因此我将首先尝试第一组索引。您是否可以尝试在iflora\u用户\u新闻稿\u地图上添加一个组合索引,其中包含用户id、新闻稿id、,激活并查看执行计划是否更改?旁注:使用显式连接而不是您提到的隐式.created复合索引,但解释计划中没有更改。解释计划中的每一行都显示键的使用情况。表格扫描在哪里?您是否可以尝试在iflora\u user\u newsletter\u map上添加一个组合索引,其中的列为user\u id、newsletter\u id、,激活并查看执行计划是否更改?旁注:使用显式连接而不是您提到的隐式.created复合索引,但解释计划中没有更改。解释计划中的每一行都显示键的使用情况。表扫描在哪里?如果你显示了你建议的索引,并且解释得更好一些,这个答案会更好一些。欢迎使用堆栈溢出。根据你的建议,我添加了索引idx_747(用户id,时事通讯id,活动),扫描行数增加,解释计划和查询性能似乎没有变化。能否粘贴新的解释以查看使用的索引?您可能需要在查询中“强制索引'idx_747'”。如果您显示了您建议的索引,并对其进行了更好的解释,则答案会稍好一些。欢迎使用堆栈溢出。根据您的建议,我添加了索引idx_747(用户id,时事通讯id,活动)扫描行数增加,解释计划和查询性能似乎没有变化。能否粘贴新的解释以查看使用的索引?您可能需要在查询中“强制索引´idx_747´”