我有一个至少包含几百万行的表和一个包含所有整数的架构,大致如下所示:
start
stop
first_user_id
second_user_id
使用以下查询提取行:
SELECT *
FROM tbl_name
WHERE stop >= M
AND first_user_id=N
AND second_user_id=N
ORDER BY start ASC
SELECT *
FROM tbl_name
WHERE stop >= M
AND first_user_id=N
ORDER BY start ASC
我无法找到加速这些查询的最佳索引。问题似乎是 ORDER BY,因为当我取出它时,查询速度很快。
我已经使用标准索引格式尝试了所有不同类型的索引:
ALTER TABLE tbl_name ADD INDEX index_name (index_col_1,index_col_2,...)
而且它们似乎都不能加快查询速度。有谁知道什么索引会起作用?另外,我应该尝试不同类型的索引吗?我无法保证每一行的唯一性,因此我避免使用 UNIQUE 索引。
任何指导/帮助将不胜感激。谢谢!
更新:这里有一个索引列表,我最初没有包括这个,因为我采用了散弹枪方法并添加了大量索引来寻找一个有效的索引:
start_index: [start, first_user_id, second_user_id]
stop_index: [stop, first_user_id, second_user_id]
F1_index: [first_user_id]
F2_index: [second_user_id]
F3_index: [another_id]
test_1_index: [first_user_id,stop,start]
test_2_index: [first_user_id,start,stop]
test_3_index: [start,stop,first_user_id,second_user_id]
test_4_index: [stop,first_user_id,second_user_id,start]
test_5_index: [stop,start]
这是 EXPLAIN 输出。
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: listing
type: index_merge
possible_keys: stop_index,F1_index,F3_index,test_1_index,test_2_index,test_4_index,test_5_index
key: F1_index,F3_index
key_len: 5,5
ref: NULL
rows: 238
Extra: Using intersect(F1_index,F3_index); Using where; Using filesort
后代更新
我们最终完全重新评估了查询表的方式并选择了这些索引:
index_select_1: [first_user_id,start,stop]
index_select_2: [first_user_id,second_user_id,start,stop]
然后我们使用如下查询在表上进行选择:
SELECT *
FROM tbl_name
WHERE first_user_id=N
AND start >= M
ORDER BY start ASC
SELECT *
FROM tbl_name
WHERE first_user_id=N
AND second_user_id=N
AND start >= M
ORDER BY start ASC
感谢所有回答的人,你们真的帮我想通了这个问题。
最佳答案
你能让你的示例表和 EXPLAIN 结果匹配吗? 因为,显然情况不同,我们不知道您是否仅通过查看提供的 EXPLAIN 结果在抽象真实查询时犯了错误。 如果您不想显示太多结构,则将其反转并创建引用的表结构并提供 EXPLAIN 结果(也许您会以这种方式发现问题)。
现在可以确定一件事 - 排序正在使用 filesort ,这很糟糕。
为了简化(我们会回来讨论它)- 用于排序的复合索引需要在前面有排序字段。
例子 idx(ID, 开始)
ID Start
1
5
8
8
10
25
2
3
9
10
40
41
42
42
...
在上面的示例中,如果您没有将 ID 限制为仅一个值的 where 条件,则索引对排序没有多大帮助。
但是,这个异常(exception)很重要,因为您在一个或两个 id 字段上有单行选择性。
所以从你的索引中,唯一从头开始的索引是
start_index: [start, first_user_id, second_user_id]
test_3_index: [start,stop,first_user_id,second_user_id]
Mysql忽略索引
start_index: [start, first_user_id, second_user_id]
因为它在选择性方面有更好的选择 - 它需要使用该索引进行索引扫描,并且它具有允许它进行索引相交直接跳转到(未排序的)结果的索引。它期望从相交处获得更好的选择性,并且选择性驱动刨床。
一旦得到结果,mysql 应该意识到它可以使用另一个索引来对结果进行排序,但它似乎看不出这样做会有多便宜。
因此,为了帮助规划者,您可以创建一个索引,该索引将利用您的单值选择性索引,例如:
two_ids_with_sort: [first_user_id, second_user_id, start]
我假设上面的方法在你的第二个查询上工作得很好,你在两个 id 上都有条件,让你可以访问预排序的开始记录指针。以下查询应该对第一个查询执行相同的操作:
one_id_with_sort: [first_user_id, start]
只有当您最终在结果集中有很多记录时,我才会考虑进一步索引它。
那里有两条路 a) 将字段停止添加到索引的末尾 b) 使用 stop 而不是 start 创建两个更相似的索引(可以在那里使用索引相交,并且更广泛的查询可以从中受益)
但请务必检验上述所有理论。
几个一般性建议
- 首先以最有选择性的方式写下您的条件
- 当测试索引首先从单列索引开始,然后扩展到复合索引时(例如,对于开始排序,我只会在开始时添加索引)
- 太多的索引在 mysql 中不是很好,因为查询规划器不能快速运行所有可能的组合并且不能正确估计所有操作的成本(所以它偷工减料,最好的索引组合和计划可能被排除在外)
- 因此,在您的选择中使用
USE INDEX (index1) FOR ORDER BY
测试索引,以衡量某个索引相对于 planer 的好处,查看更多 here (特别是 FORCE 选项;还有——旨在只留下有用的索引,看看 planer 是否能够利用它们,如果不能,作为最后的手段,在你的查询中强制使用性能至关重要的索引。记住这在管理和设计方面是一种不好的做法)。
关于sql - 使用大于运算符和 ORDER BY 的 MySQL 查询的索引帮助,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2405128/