我在 MariaDB 10.4.12 中运行一个简单的查询:
SELECT *
FROM transazioni tr
LEFT JOIN acqurienti a ON tr.acquirente=a.id
WHERE
tr.frontend=1
AND tr.stato!=0
AND a.cognome LIKE 'AnyText%'
ORDER BY tr.creazione
该表有以下索引:
frontend
基数为 166 的 int 字段creazione
基数为 123541 的数据时间字段(表的所有行)
这是它的解释:
+-----+--------------+--------+---------+-----------------------------------------+------------+----------+------------------------------------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+-----+--------------+--------+---------+-----------------------------------------+------------+----------+------------------------------------+-------+-------------+
| 1 | SIMPLE | tr | index | acquirente,frontend | creazione | 6 | NULL | 793 | Using where |
| 1 | SIMPLE | a | eq_ref | PRIMARY | PRIMARY | 4 | tr.acquirente | 1 | Using where |
+-----+--------------+--------+---------+-----------------------------------------+------------+----------+------------------------------------+-------+-------------+
由于某种原因,它需要大约 12 秒,因为它使用
creazione
索引,即日期时间。
如果我删除
ORDER BY creazione
,它会加速到 0.4 秒,其解释将更改为:
+-----+--------------+--------+---------+-----------------------------------------+---------------------+----------+----------------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+-----+--------------+--------+---------+-----------------------------------------+---------------------+----------+----------------+-------+-------------+
| 1 | SIMPLE | tr | ref | acquirente,frontend | frontend | 5 | const | 3112 | Using where |
| 1 | SIMPLE | a | eq_ref | PRIMARY | PRIMARY | 4 | tr.acquirente | 1 | Using where |
+-----+--------------+--------+---------+-----------------------------------------+---------------------+----------+----------------+-------+-------------+
我无法理解为什么由于 ORDER BY 关键字切换到更差的基数而导致键发生变化。据我所知,ORDER 是在 where 之后应用的,在此示例中,where 过滤器将结果集限制为仅 2 行。
我知道解决方案可以将
frontend
索引更改为 (frontend,creazione)
并删除单个 creazione
索引,但我缺少键选择的逻辑。此外,我可能需要单个 creazione
索引来进行其他一些查询。
为什么order by会欺骗索引选择?
看起来
LEFT JOIN
真的是JOIN
。 鉴于此,优化器可以从任一表开始。
这些应该对任何一种情况都有帮助:
tr: INDEX(frontend, creazione)
tr: INDEX(frontend, acquirente)
a: INDEX(cognome)