【问题标题】:Indexes when left joining 2 tables with order by on second table MySQL在第二个表 MySQL 上按顺序加入 2 个表时的索引
【发布时间】: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

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

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

提前致谢

【问题讨论】:

    标签: php mysql indexing left-join


    【解决方案1】:

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

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

    【讨论】:

      猜你喜欢
      • 2021-10-19
      • 1970-01-01
      • 2016-11-05
      • 1970-01-01
      • 2020-12-27
      • 1970-01-01
      • 2012-12-26
      • 2020-08-08
      • 1970-01-01
      相关资源
      最近更新 更多