当join on子句中提到字段时,未获取mysql索引

mdfafbf1  于 2021-06-20  发布在  Mysql
关注(0)|答案(2)|浏览(305)
explain select * from users u join wallet w on w.userId=u.uuid where w.userId='8319611142598331610'; //Index is taken

explain select * from users u join wallet w on w.userId=u.uuid where w.currencyId=8; //index is not taken


如上所述,索引userididx用于后一种情况,但不用于前一种情况。
以下是两个表的架构-

CREATE TABLE `users` (
  `uuid` varchar(600) DEFAULT NULL,
  KEY `uuidIdx` (`uuid`),
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE `wallet` (
  `Id` int(11) NOT NULL AUTO_INCREMENT,
  `userId` varchar(200) NOT NULL DEFAULT '',
  `currencyId` int(11) NOT NULL,
  PRIMARY KEY (`Id`),
  KEY `userIdIdx` (`userId`),
  KEY `currencyIdIdx` (`currencyId`)
) ENGINE=InnoDB AUTO_INCREMENT=279668 DEFAULT CHARSET=latin1;

如何强制mysql考虑 userIdIdx 或者 uuidIdx 索引?

mv1qrgav

mv1qrgav1#

这两个查询都在尽最大努力处理您提供给它们的内容。

select  *
    from  users u
    join  wallet w  ON w.userId=u.uuid
    where  w.userId='8319611142598331610';

select  *
    from  users u
    join  wallet w  ON w.userId=u.uuid
    where  w.currencyId=8;

如果表中只有一行(例如 users ),优化器采用不同的路径。第一个查询似乎就是这样。
否则,两个查询都将以 wallet 因为正在进行过滤。中的每个辅助键 wallet 对于其中一个查询很方便。更好的是

INDEX(userId, currencyId, id)  -- for first query
INDEX(currencyId, userId, id)  -- for second query

第一列用于 WHERE ; 另外两列使索引“覆盖”,这样就不需要在索引和数据之间跳转。
(天哪,那些表的列太少了。)
过滤后 w ,它将转到 u 和用途 INDEX(uuid) . 因为那是表中唯一的一列,(没有名字??),所以它可以是“using index”,也就是“covering”。
唯一的原因是 u 验证是否存在值匹配的用户 w.userId . 既然你可能一直都这样,为什么 JOINusers 在所有的查询中??

whhtz7ly

whhtz7ly2#

有两种方法可以改进这一点。
方法1:
添加多列索引 wallet(userId, currencyId) 这两个查询看起来都更好。
请参见演示https://www.db-fiddle.com/f/aesnyevezwopmxrnqjrpos/0
方法2
重写查询。
这适用于当前的表结构。
查询

SELECT 
 *
FROM (
  SELECT 
   wallet.userId
  FROM 
   wallet 
  WHERE
   wallet.currencyId = 8
) AS wallet
INNER JOIN 
 users
ON
 wallet.userId = users.uuid

请参见演示https://www.db-fiddle.com/f/aesnyevezwopmxrnqjrpos/3
p、 我也建议你也加上 Id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY 当您使用innodb作为表引擎时,可以将其添加到users表。我的帖子解释了原因https://dba.stackexchange.com/a/48184/27070

相关问题