在第二个表 MySQL 上按顺序加入 2 个表时的索引

Posted

技术标签:

【中文标题】在第二个表 MySQL 上按顺序加入 2 个表时的索引【英文标题】:Indexes when left joining 2 tables with order by on second table MySQL 【发布时间】:2021-07-22 10:51:19 【问题描述】:

对于有经验的用户来说这可能很容易,但我无法完全理解这个简单案例需要哪些索引。

除了一些可用于搜索目的的过滤器之外,我有一个可以按任何列排序的前端表:

id | username | email | name | phone | email_verified_at

显示的行是连接 2 个表的结果(具有一对一关系):

TABLE USERS

id | autoincrement
name | string
username | string | unique
email | string | unique
email_verified_at | timestamp | nullable

INDEXES
primary(id)
unique(name,id)
unique(username)
unique(email)
unique(email_verified_at,email)
TABLE PROFILES

id | autoincrement
user_id | FK(users)
phone | string

INDEXES
primary(id)
index(user_id)
unique(phone,user_id)

最基本的查询,按用户id排序

select
  `users`.`id` as `id`,
  `users`.`name` as `name`,
  `users`.`username` as `username`,
  `users`.`email` as `email`,
  `users`.`email_verified_at` as `email_verified_at`,
  `profiles`.`phone` as `phone`
from
  `users`
  left join `profiles` on `users`.`id` = `profiles`.`user_id`
order by
  `id` asc
limit
  11

按 id、姓名、用户名、电子邮件或 email_verified_at 排序在用户表中执行全索引扫描,我认为这是正确的。

但是当我尝试通过电话订购时,麻烦(或没有)来了:

select
  `users`.`id` as `id`,
  `users`.`name` as `name`,
  `users`.`username` as `username`,
  `users`.`email` as `email`,
  `users`.`email_verified_at` as `email_verified_at`,
  `profiles`.`phone` as `phone`
from
  `users`
  left join `profiles` on `users`.`id` = `profiles`.`user_id`
order by
  `phone` asc
limit
  11

我看到的第一件事是它正在用户表中进行全表扫描。 为了避免我需要为包含以下内容的用户表创建一个唯一索引:

id, username, email, name

因此,查询对用户表执行全索引扫描。 尽管如此,与按用户表字段排序相比,我发现查询成本太高了。

这样好吗?我在这里错过了什么吗?我不确定这是预期结果还是可以改进。

提前致谢

【问题讨论】:

【参考方案1】:

profiles 需要一个以user_id 开头的索引。索引中列的顺序很重要。

如需进一步讨论,请提供SHOW CREATE TABLEEXPLAIN FORMAT=JSON SELECT ...

【讨论】:

以上是关于在第二个表 MySQL 上按顺序加入 2 个表时的索引的主要内容,如果未能解决你的问题,请参考以下文章

MySQL LEFT JOIN 在第二个表中具有可选值

如果一个表的列等于第二个表中的列,则在第三个表中插入值,python - mysql

Excel:使用一个表中的值在第二个表中查找值

sql server 2000返回在第一个表中但不在第二个表中的数据

左外连接 - 如何在第二个表中返回一个布尔值?

我有两个带外键的表,我想在第一个表中按下外键,第二个表出现数据