【问题标题】:How composite index and left join work in MySql?复合索引和左连接如何在 MySql 中工作?
【发布时间】:2020-09-24 05:17:12
【问题描述】:

我有两张如下表

我在两个表上都有如下复合索引:

  • users 表有一个复合索引:(login_type_id, language_id, enabled, level)

  • 地址表有复合索引:(user_id, city_id, enabled)

我想执行以下查询

select * from users u
left join address adr
on u.id = adr.user_id
where u.login_type_id = 1
and u.langauge_id = 1
and u.enabled = true
and adr.city_id in (1,2,3,4,5)
and adr.enabled = true
order by u.level

当我执行查询时,我希望 MySQL 在两个表上都使用复合索引,因为 where 子句中的所有字段都已编入索引。但是MySql使用地址表作为base,只使用用户的主键加入。

连接两个表时MySql会忽略复合索引吗?

你们能告诉我为什么 MySql 不在两个表上都使用复合索引吗?

为了使查询最快,请问我应该在哪些字段上创建索引?

谢谢。

解释 SQL

请注意,实际数据库与问题中的数据库不同,但关系和索引是相同的。

【问题讨论】:

  • 如果包含EXPLAIN {query} 信息可能会更容易。哪个 MySQL 版本?
  • @danblack hellp danblack,非常感谢您的评论,我刚刚上传了MySql解释我的查询的结果。我正在使用 Mysql 版本 8.0.19。
  • MySQL-8.0.verynew 有 EXPLAIN ANALYZE {query} 显示更多信息。同样来自您的EXPLAIN,您的数据集似乎只有 3 行。如果您想更确定在给定这些索引的情况下什么是标准 MySQL 查询计划,则需要更大的样本。
  • 请停止猜测。这些表针对多个页面进行了“抽样”,并且这些样本页面与搜索条件相匹配,以查看其可能包含的较低查询成本。
  • 我认为 MySql 会使用那些复合键,因为我在“复合索引”中索引了“where”子句中的那些字段。它们的表达式必须以使用的字段开头加入! WHERE 中使用的字段必须是索引表达式的其余部分。

标签: mysql database optimization indexing


【解决方案1】:
  • 当您在LEFT JOIN 的“右”表上有约束(参见WHERE)时;优化器将把它变成一个普通的JOIN。这允许它重新排列表格。

  • PRIMARY KEY 通常是将JOIN 发送到表的最佳方式。

  • “覆盖”INDEX 具有所有查询所需的列。由于您指定了SELECT *,因此您要求的是full_name,它在您的索引中缺失,因此它不是“覆盖”。

  • 索引中列的顺序可能非常重要。 (但在您的示例中没有。)这可能导致不使用复合索引,甚至可能导致不使用覆盖索引。

  • 一般情况下,最好将=测试的列放在复合索引的最前面。

  • 如果不是覆盖索引,优化器将停在复合索引的第一个“范围”列。 (与您的示例无关。)

  • IN(1,2,3,4) 可能会像 = 或范围一样优化,具体取决于月相。

  • 复合索引的组件的基数在排列列时并不重要。

  • 如果优化器认为它需要访问的索引超过了索引的 20%,它将避开索引并使用表扫描。

更多:http://mysql.rjweb.org/doc.php/index_cookbook_mysqlhttp://mysql.rjweb.org/doc.php/index1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-01
    • 2012-08-08
    • 2014-02-17
    • 2013-03-20
    • 1970-01-01
    • 2015-08-24
    • 2020-06-04
    相关资源
    最近更新 更多