Mysql 表索引良好,但执行查询需要很长时间?

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_

我们的一个查询是扫描整个表,它占用了所有的时间 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_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´”