小提琴:https ://www.db-fiddle.com/f/m4vsq4ERyBhiBNdZqALMVP/0
我有两个索引,一个 forsome_other_id
和一个 for created_at , some_other_id
。
选择查询使用生产服务器上的第一个索引(~23M 行),而它使用我的开发机器上的第二个索引(1 行)。
服务器说明:
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: symbol_details
type: ref
possible_keys: symbol_details_some_other_id_index,symbol_details_created_at_some_other_id_index
key: symbol_details_some_other_id_index
key_len: 8
ref: const
rows: 24152
Extra: Using where
开发说明:
id: 1
select_type: SIMPLE
table: symbol_details
type: range
possible_keys: symbol_details_some_other_index,symbol_details_created_at_some_other_id_index
key: symbol_details_created_at_some_other_id_index
key_len: 5
ref: NULL
rows: 1
Extra: Using where; Using index
同样在小提琴中,它没有使用第二个索引,而显然对created_at
.
是因为行数吗?
我想在生产中使用这样的查询,但是这样太慢了。像这样的单个查询会返回约 23M 行中的约 100 行,我认为第二个索引会涵盖此查询,但它似乎以某种方式没有。
关于如何使用索引的任何想法,或为此查询创建另一个索引,或修改查询以使用索引。
最好的解决方案是不触及查询,因为它是由 ORM 生成的。在使用 ORM 时在查询中使用提示并不完全干净,但如果它是唯一的选择是可行的。
谢谢!
开发 Mariadb 版本 10.4.13 和生产版本是 10.4.12(在 docker btw 中运行)。
编辑:
第一个索引正在其他地方使用,它需要在那里(索引 on some_other_id
)。也许我可以将两个索引合并到on中?IDK还没有。
EDIT2 为什么我选择有两个索引:
由于some_other_id
的基数是 ~70k 并且created_at
是 ~400k 我选择有第二个索引首先过滤created_at
。现在我在想我这样想是否正确。
最佳索引,按此顺序:
当您从范围值开始时,它无法超过“id”。简单的规则是:将
=
列放在索引定义的首位。更多:http: //mysql.rjweb.org/doc.php/index_cookbook_mysql补充说明
优化器可能会决定表扫描比使用
INDEX
. 这通常发生在需要触摸超过大约 20% 的表格时。(使用索引意味着在索引的 BTree 和数据的 BTree 之间来回跳转。)如果它避开索引,请不要担心;这可能是一个明智的决定。当涉及“范围”时,索引中列的顺序至关重要。一旦超过“范围”,优化器将停止考虑列。