【问题标题】:Has anyone ever successfully make index merge work for MySQL?有没有人成功地使索引合并为 MySQL 工作?
【发布时间】:2023-03-30 04:00:01
【问题描述】:

设置:

mysql> create table t(a integer unsigned,b integer unsigned);
mysql> insert into t(a,b) values (1,2),(1,3),(2,4);
mysql> create index i_t_a on t(a);
mysql> create index i_t_b on t(b);
mysql> explain select * from t where a=1 or b=4;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | t     | ALL  | i_t_a,i_t_b   | NULL | NULL    | NULL |    3 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+

我有什么遗漏吗?

更新

mysql> explain select * from t where a=1 or b=4;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | t     | ALL  | i_t_a,i_t_b   | NULL | NULL    | NULL | 1863 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+

版本

mysql> select version();
+----------------------+
| version()            |
+----------------------+
| 5.1.36-community-log |
+----------------------+

有没有人成功地使索引合并为 MySQL 工作?

我很高兴在这里看到成功的故事:)

【问题讨论】:

    标签: mysql sql-optimization


    【解决方案1】:

    我不知道这是否是实际的原因,但我认为任何值得一提的 DBMS 都会看到“rows = 3”属性并决定甚至不值得查看索引.您可以对三行进行全表扫描的速度将使任何其他方法都毫无意义。

    尝试用几千行做同样的事情,看看是否得到相同的结果。


    来自here,评论者指出“我测试的表导致索引合并联合版本在某些情况下不使用任何索引”,尽管他们似乎不知道这些情况是什么,确切地说: -) 这可能也是您可以向 MySQL 支持小组(和开发人员)提出的问题。

    只是出于兴趣,以下查询从 EXPLAIN 中为您提供了什么:

    select * from t where a=1
    union
    select * from t where b=4;
    

    可能是 MySQL 正在根据表本身的数据评估是否使用索引联合。如果只有a 的2 个变体和b 的3 个变体,它可能会再次决定您的查询无论如何都会返回大部分行,因此不必为优化而烦恼。

    您可以尝试使用大量行ab 列中的大量值。

    请记住,这不是基于我对 MySQL 的了解,我从未见过代码库或使用过该产品。但是,我在某个主流数据库产品上做了一些工作 - 所以这个建议是基于我对高效做事的理解,这可能不适用于 MySQL,实际上可能通常情况并非如此:-)

    【讨论】:

    • 你能给出一个 index_merge 工作的演示吗?对于你更新的问题,这是一个带有两个 refUNION。我遇到的问题是不是在某些情况下,而是在所有情况下......
    • 不,不是真的,我不是 MySQL 用户,只是根据我对 DBMS 内部的一般知识提出建议(请参阅更新)。这就是为什么这个答案是 CW - 对于您的特定情况,它可能完全是废话。
    • 哦,你还没有真正使用过 MySQL,但是如果你发布一个在其他 DBMS 中工作的演示,那很好。如果相同的设置在其中工作,那么它可能是一个错误或一个功能 MySQL还没实现?
    • MySQL 优化器非常复杂,需要考虑很多事情,包括列的基数,所以我认为你在正确的轨道上@paxdiablo。 @user198729 关于行数,我认为在优化器决定使用索引之前您可能需要更多。大约 8 个字节(2 个整数列)中的每行 2000 行加起来大约只有 16KB。在这种大小下,全表扫描可能仍然非常有效,并且不需要索引来提高性能。
    • @Jarod Elliott,你能发布一个真正有效的演示吗?我还没有看到一个有效的演示。不要根据表格的大小来推理一切,请参阅我的第二条评论,使用索引即使只存在几条记录...
    【解决方案2】:

    长背:

    显示来自lesssong的索引;

    Table, Non_unique, Key_name, Seq_in_index, Column_name, Collation, Cardinality, Sub_part, Packed, Null, Index_type, Comment
    'lesssong', 0, 'PRIMARY', 1, 'S_ID', 'A', 50000, , '', '', 'BTREE', ''
    'lesssong', 1, 'idx_s_name', 1, 'S_NAME', 'A', 25000, 10, '', '', 'BTREE', ''
    'lesssong', 1, 'idx_S_ARID', 1, 'S_ARID', 'A', 1315, , '', '', 'BTREE', ''
    'lesssong', 1, 'idxFTS', 1, 'S_NAME', '', 1, , '', '', 'FULLTEXT', ''
    

    计数 = 50000

    解释 select * from lesssong where s_name='kv' or s_arid=4

    1, 'SIMPLE', 'lesssong', 'index_merge', 'idx_s_name,idx_S_ARID,idxFTS', 'idx_s_name,idx_S_ARID', '12,4', '', 2, 'Using sort_union(idx_s_name,idx_S_ARID); Using where'
    

    结构:

    'S_ID', 'int(10) unsigned', 'NO', 'PRI', '', 'auto_increment'
    'S_ALID', 'int(10) unsigned', 'NO', '', '', ''
    'S_ARID', 'int(10) unsigned', 'NO', 'MUL', '', ''
    'S_NAME', 'varchar(100)', 'NO', 'MUL', '', ''
    'S_LYRIC', 'text', 'NO', '', '', ''
    'S_WRITER', 'varchar(45)', 'NO', '', '', ''
    'S_LINK', 'varchar(255)', 'NO', '', '', ''
    

    即使是你的结构,我也得到了它的工作:

    我添加了随机 100 个值:

    insert into t(a,b) select ceil(rand()*5),ceil(rand()*30)
    

    说明 select * from t where a=1 or b=4;

    id, select_type, table, type, possible_keys, key, key_len, ref, rows, Extra
    1, 'SIMPLE', 't', 'index_merge', 'i_t_a,i_t_b', 'i_t_a,i_t_b', '5,5', '', 32, 'Using union(i_t_a,i_t_b); Using where'
    

    【讨论】:

    • 你能把lesssong的架构贴在这里吗?
    • 我已经向您展示过的结构。因为这也适用于你的模式,对我来说也是如此。主要是数据。尝试像我使用插入随机数一样为您的模式生成数据。然后执行相同的查询。它应该做。根据数据mysql将决定什么是最佳的执行方式。
    • 如果你运行insert into t(a,b) select ceil(rand()*5),ceil(rand()*30) 很多次,它会不起作用,可能只有10次。
    • 10次不是很多!!当然 mysql 可能不会对此类数据使用合并索引!我已经执行了 100 次它对我有用!让我看看向您展示的选项...
    • 好的,我在这里: 1) 转到db4free.net/phpMyAdmin-3.3.1 2) 用户名​​:kedar 密码:indexmerge 3) 使用数据库 ksql 4) 执行:解释 select * from t where a=1 or b =4;我希望你能看到自己。
    【解决方案3】:

    太糟糕了,没有办法强制 MySQL 使用合并,比如当它默认选择错误的索引时如何强制它使用特定的索引(很少发生,但我已经看到它并且不得不处理和它)。

    我猜这仅仅是因为您的数据没有足够的基数让 MySQL 决定值得花时间使用索引,更不用说 index_merge。 1800 行算不了什么 - 真的。创建至少一百万行,并使每一行都独一无二。然后它可能会做你想做的事。对于这么小的表,索引并不能真正为您做任何事情。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-12-31
      • 1970-01-01
      • 2023-04-09
      • 1970-01-01
      • 2013-04-21
      • 1970-01-01
      • 2014-08-16
      • 1970-01-01
      相关资源
      最近更新 更多