这是我的表定义:
CREATE TABLE difficulty (
uuid binary(16) NOT NULL,
createdTimestamp datetime(6) DEFAULT NULL,
modifiedTimestamp datetime(6) DEFAULT NULL,
name varchar(255) DEFAULT NULL,
PRIMARY KEY (uuid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE exercise_session (
uuid binary(16) NOT NULL,
createdTimestamp datetime(6) DEFAULT NULL,
modifiedTimestamp datetime(6) DEFAULT NULL,
type varchar(16) DEFAULT NULL,
status int(11) DEFAULT NULL,
difficulty_uuid binary(16) DEFAULT NULL,
PRIMARY KEY (uuid),
KEY (difficulty_uuid),
KEY (difficulty_uuid,modifiedTimestamp),
KEY (modifiedTimestamp),
KEY (status),
FOREIGN KEY (difficulty_uuid) REFERENCES difficulty (uuid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
这是我的疑问:
SELECT s.difficulty_uuid, s.modifiedTimestamp, d.name
FROM exercise_session s
INNER JOIN difficulty d ON s.difficulty_uuid=d.uuid
ORDER BY s.modifiedTimestamp DESC
LIMIT 20
一些数据:
INSERT INTO difficulty (uuid, createdTimestamp, modifiedTimestamp, name) VALUES
(0x00000000000000000000000000000000, NULL, NULL, 'difficulty');
INSERT INTO exercise_session (uuid, createdTimestamp, modifiedTimestamp, type, status, difficulty_uuid) VALUES
(0x00000000000000000000000000000000, NULL, '2017-09-09 03:47:42.000000', '0', 0, 0x00000000000000000000000000000000),
(0x00000000000000000000000000000001, NULL, '2017-09-09 03:47:42.000000', '0', 0, 0x00000000000000000000000000000000);
当我运行前缀为EXPLAIN
的查询时,这是输出:
+------+-------------+-------+------+-----------------+-----------------+---------+--------------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+------+-----------------+-----------------+---------+--------------+------+---------------------------------+
| 1 | SIMPLE | d | ALL | PRIMARY | NULL | NULL | NULL | 1 | Using temporary; Using filesort |
| 1 | SIMPLE | s | ref | difficulty_uuid | difficulty_uuid | 17 | dbname.d.uuid | 1 | |
+------+-------------+-------+------+-----------------+-----------------+---------+--------------+------+---------------------------------+
为什么MySQL / MariaDB执行文件排序而不是使用复合索引?
答案 0 :(得分:2)
在对优化程序对它们的处理做出结论之前,您应该用更多的测试数据填充这些表。在每个表中只有一行或两行可能会触发非典型的优化器计划。
我尝试用几十行填充表格,并得到了这个EXPLAIN:
%matplotlib tk
仍然是一个文件分区,但至少它以正确的顺序访问了表:*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: s
partitions: NULL
type: index
possible_keys: difficulty_uuid,difficulty_uuid_2
key: difficulty_uuid_2
key_len: 26
ref: NULL
rows: 11
filtered: 100.00
Extra: Using where; Using index; Using filesort
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: d
partitions: NULL
type: eq_ref
possible_keys: PRIMARY
key: PRIMARY
key_len: 16
ref: test.s.difficulty_uuid
rows: 1
filtered: 100.00
Extra: NULL
首先,然后加入其主键上的s
,从而产生d
类型的访问权限。
使用索引提示表扫描成本太高而无法考虑,它使用modifiedTimestamp上的索引:
eq_ref
不再是任何文件存储,但我们看到向后索引扫描这是MySQL 8.0中的新功能(我使用预览版本进行测试)。
介绍此功能的博客http://mysqlserverteam.com/mysql-8-0-labs-descending-indexes-in-mysql/提到MySQL 5.7可以向后扫描索引,但它比进行正向索引扫描的成本高出约15%。 Jeremey Cole已经在InnoDB index internals上做了博客和演示,我记得他确切地说明了为什么降序索引扫描成本更高,但我不能清楚地回想起它来解释这里。
答案 1 :(得分:1)
查看EXPLAIN
的内容,特别是有多行:
SELECT s.difficulty_uuid, s.modifiedTimestamp,
(
SELECT name
FROM difficulty
WHERE uuid = s.difficulty_uuid
) AS name
FROM exercise_session s
ORDER BY s.modifiedTimestamp DESC
LIMIT 20
顺便说一下,当你拥有庞大的桌子时,UUID很糟糕。除了一些“分布式”架构情况外,并不是真正需要的。请考虑AUTO_INCREMENT
的用户。
答案 2 :(得分:0)
我们通过不加入难度来解决问题,而是使用" WHERE IN"来做一个查询。之后加载所有这些。
@Bill Karwin建议的修复程序不起作用,因为我们没有使用MySQL 8.0(尤其不是预览版)。在MariaDB 10.2.8下它没有用。
里克詹姆斯'建议也不起作用,因为我们从difficulty
表中加载了多个列。