【问题标题】:Issue with MySQL explain plan, multiple-field indices and OR clauseMySQL 解释计划、多字段索引和 OR 子句的问题
【发布时间】:2023-11-16 02:40:02
【问题描述】:

我有一个我不理解的解释计划结果。我有下表包含从sendersrecipients 发送的消息。

CREATE TABLE `message` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `message_read` bit(1) NOT NULL,
  `send_date` datetime NOT NULL,
  `text` varchar(500) NOT NULL,
  `version` int(11) DEFAULT NULL,
  `recipient` bigint(20) NOT NULL,
  `sender` bigint(20) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `index4` (`recipient`,`sender`) USING BTREE,
  KEY `index5` (`sender`,`recipient`) USING BTREE,
  CONSTRAINT `FK_a3km2kv42i1xu571ta911f9dc` FOREIGN KEY (`sender`) REFERENCES `member` (`id`),
  CONSTRAINT `FK_hn9roqyj131hnul5fuwgwlv9e` FOREIGN KEY (`recipient`) REFERENCES `member` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8;

这是我的解释计划:

explain select *
    from
        message m 
    where
        (
            m.sender = 1
            and m.recipient= 2
        ) 
        or (
            m.recipient = 1 
            and m.sender= 2 
        ) 

这是我解释计划的结果:

我不确定为什么 key 字段是 nullpossible_keys 确实提到了我想使用的索引)。

如何确保使用 index4index5 索引?

编辑 1

我在表格中插入了许多行。下面解释一下:

explain select *
    from
        message m FORCE INDEX(index4) 
    where
        (
            m.sender = 1
            and m.recipient= 2
        ) 
        or (
            m.sender= 2 
            and m.recipient = 1 
        )

现在产生以下结果:

1   SIMPLE  m   range   index4  index4  16      32  Using where

【问题讨论】:

  • 只能使用一个索引
  • @草莓。谢谢。有没有办法重写我的查询以使用一个索引?

标签: mysql jpa jpql explain sql-execution-plan


【解决方案1】:

为了强制使用索引,可以使用 FORCE INDEX...

SELECT * 
  FROM message FORCE INDEX(index4) 
 WHERE ((recipient = 2 AND sender = 1) OR (recipient=1 AND sender = 2));

在 32 行的表上,这可能比全表扫描效率低。

【讨论】:

  • 欧普斯。我使用 JPA 来生成我的查询...还有其他使用索引的方式吗?
  • 生产中将有超过 100K 行... :-)
  • 我怀疑优化器会在认为这样做有益时使用索引。
  • 你的意思是说表中的数据越多,解释计划就会给出不同的结果并且索引会被使用?
  • 是的。其他人将能够解释它的机制,但是这么小的表可能根本不使用(非主)索引。
最近更新 更多