MySQL 索引未按预期使用

标签 mysql sql query-optimization primary-key composite-primary-key

如何使 mysql 使用预期的索引?

我有 4 个表,两个包含资源,其他包含历史更改。

一对正确使用索引,另一对不正确,但两者的结构几乎相同。

我试过改变主键的顺序,以及其他键的顺序,我试过改变表结构,使它们在两个表中使用相同的名称,并且都具有相同的键名,但没有似乎使查询使用了正确的索引。

为简洁起见,已删除不相关的列。

这两个表按预期工作。

CREATE TABLE `players` (
  `player_id` varbinary(36) NOT NULL DEFAULT '',
  `pop_rank_score` double NOT NULL DEFAULT '0',
  PRIMARY KEY (`player_id`),
  KEY `pop_rank_score` (`pop_rank_score`),
  KEY `weblinc_id` (`weblinc_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

CREATE TABLE `poprankhistory` (
  `day_id` int(11) NOT NULL,
  `player_id` varbinary(36) NOT NULL DEFAULT '',
  `total` double NOT NULL DEFAULT '0',
  `today` double NOT NULL DEFAULT '0',
  PRIMARY KEY (`day_id`,`player_id`),
  KEY `day_id` (`day_id`),
  KEY `player_id` (`player_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1


explain select p.`player_id`, p.pop_rank_score + 0.5 * COALESCE(h1.total,0) as pop_rank_score
from fpme_lua.`Players` p, fpme_lua.PopRankHistory h1
where ( p.`player_id` = h1.`player_id` AND h1.day_id = (SELECT Max(h2.day_id) AS day_id
  FROM   fpme_lua.poprankhistory h2
  WHERE  h2.day_id <= 15786 and h2.player_id = p.`player_id` ));

+----+--------------------+-------+--------+--------------------------+-----------+---------+-----------------------+-------+--------------------------+
| id | select_type        | table | type   | possible_keys            | key       | key_len | ref                   | rows  | Extra                    |
+----+--------------------+-------+--------+--------------------------+-----------+---------+-----------------------+-------+--------------------------+
|  1 | PRIMARY            | h1    | ALL    | PRIMARY,day_id,player_id | NULL      | NULL    | NULL                  | 25391 |                          |
|  1 | PRIMARY            | p     | eq_ref | PRIMARY                  | PRIMARY   | 38      | fpme_lua.h1.player_id |     1 | Using where              |
|  2 | DEPENDENT SUBQUERY | h2    | ref    | PRIMARY,day_id,player_id | player_id | 38      | fpme_lua.p.player_id  |     2 | Using where; Using index |
+----+--------------------+-------+--------+--------------------------+-----------+---------+-----------------------+-------+--------------------------+

这些表没有按预期工作(必需)。

CREATE TABLE `pictures` (
  `id` varchar(36) NOT NULL DEFAULT '',
  `pcr_score` double NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `owner_id` (`owner_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

CREATE TABLE `picpcrhistory` (
  `day_id` int(11) NOT NULL,
  `target_id` varchar(36) NOT NULL DEFAULT '',
  `total` double NOT NULL DEFAULT '0',
  `today` double NOT NULL DEFAULT '0',
  PRIMARY KEY (`day_id`,`target_id`),
  KEY `target_id` (`target_id`),
  KEY `day_id` (`day_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1


explain select p.`id`, p.pcr_score + 0.5 * COALESCE(h1.total,0) as pcr_score
from fpme_lua.`Pictures` p, fpme_lua.PicPcrHistory h1
where ( p.`id` = h1.`target_id` AND h1.day_id = (SELECT Max(h2.day_id) AS day_id
  FROM   fpme_lua.PicPcrHistory h2
  WHERE  h2.day_id <= 15786 and h2.`target_id` = p.`id` ));

+----+--------------------+-------+--------+----------------+---------+---------+------+-------+--------------------------+
| id | select_type        | table | type   | possible_keys  | key     | key_len | ref  | rows  | Extra                    |
+----+--------------------+-------+--------+----------------+---------+---------+------+-------+--------------------------+
|  1 | PRIMARY            | h1    | ALL    | PRIMARY,day_id | NULL    | NULL    | NULL | 65310 |                          |
|  1 | PRIMARY            | p     | eq_ref | PRIMARY        | PRIMARY | 110     | func |     1 | Using where              |
|  2 | DEPENDENT SUBQUERY | h2    | range  | PRIMARY,day_id | day_id  | 4       | NULL | 21824 | Using where; Using index |
+----+--------------------+-------+--------+----------------+---------+---------+------+-------+--------------------------+

最佳答案

这些表有不同的字符集,这就是索引不起作用的原因。 我更改了字符集,因此它们都是 utf8 并为三列添加了索引。

ALTER TABLE `fpme_lua`.`colpcrhistory` CHARACTER SET = utf8 ;
ALTER TABLE `fpme_lua`.`picpcrhistory` CHARACTER SET = utf8 ;
ALTER TABLE `fpme_lua`.`picpcrhistory` 
ADD INDEX `indx_tar_day_tot` USING BTREE (`target_id` ASC, `day_id` ASC, `total` ASC) ;

然后我将查询更改为...

SELECT p.id, 
       p.pcr_score + 0.5 * COALESCE(h1.total,0) AS pcr_score
FROM 
    fpme_lua.Pictures AS p
  JOIN 
    fpme_lua.PicPcrHistory AS h1
      ON  h1.target_id = p.id 
  JOIN
    ( SELECT   hh.target_id,
               Max(hh.day_id) AS day_id
      FROM     fpme_lua.PicPcrHistory AS hh
      WHERE    hh.day_id <= 15786 
      GROUP BY hh.target_id
    ) AS h2
      ON  h2.target_id = h1.target_id
      AND h2.day_id = h1.day_id ;

关于MySQL 索引未按预期使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16350794/

相关文章:

mysql - 每 1 小时自动通过 SSH 隧道对远程 mysql 服务器运行一次 select 语句

SQL:优化 DateTime 字段上的密集 SELECT

python - 存储和检索数组的最快方法

MySQL向表中的UUID添加破折号

mysql - 使用批处理文件以被动模式安装MySQL Community 5.6.14(在win7上)

mysql 检查讲师是否可以在选定的时间上课

sql - 聚合合并到Elasticsearch的匹配中

mysql - 我怎样才能优化这个查询

mysql - 为什么 LEFT JOIN 比 INNER JOIN 慢?

sql - 使用时间戳查询 MySQL 数据库