【问题标题】:Are simple where clauses executed before wildcard LIKE clauses?简单的 where 子句在通配符 LIKE 子句之前执行吗?
【发布时间】:2021-09-01 15:10:58
【问题描述】:

这里很简单(我希望)。

我想知道 MySQL 是否足够聪明,可以在不能使用索引的通配符子句之前优化/运行简单的 WHERE 子句,例如WHERE LIKE '%abc%'

例如,考虑下表:

CREATE TABLE `users` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `organization_id` bigint unsigned NOT NULL,
  `name` varchar(100) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `users_name_index` (`name`),
  KEY `users_organization_id_foreign` (`organization_id`),
  CONSTRAINT `users_organization_id_foreign` FOREIGN KEY (`organization_id`) REFERENCES `organizations` (`id`) ON DELETE CASCADE
)

并考虑以下查询:

SELECT * FROM `users` 
WHERE `organization_id` = 1
AND `name` LIKE '%abc%'

我知道由于通配符前缀,MySQL 无法使用name 上的索引。但是,MySQL 可以使用外键 organization_id 来过滤结果。

所以,问题是,MySQL 是否足够聪明,可以获取具有organization_id1 的用户,然后对生成的数据集执行通配符查找?或者,反之亦然(MySQL 将首先执行通配符搜索,然后将这些结果限制为具有 organization_id1 的记录?

更新

这是EXPLAIN 计划的结果:

【问题讨论】:

  • 对于您的具体示例,最好的办法是到check the execution plan 并确定查询是否使用origanisation_id 上的索引。作为一般规则,尽管这取决于。虽然使用organisation_id 上的索引可能很有效,但执行书签查找然后获取其他列的成本可能会超过首先执行聚集索引扫描的成本。这将根据具体情况而有所不同
  • 运行EXPLAIN SELECT * FROM users` WHERE organization_id = 1 AND name LIKE '%abc%' `
  • 感谢 cmets,我已将 EXPLAIN 结果添加为屏幕截图。
  • a brief test看来,MySQL 已经“足够聪明”地使用索引,但不够聪明,无法在应该忽略它的时候忽略它。在链接的示例中,搜索组织 ID 1 的查询实际上比创建索引之前快 10 倍,但如果存在,MySQL 仍然使用它。并不能真正回答您的问题,但值得注意的是,仅仅因为存在索引,并不一定意味着应该使用它,即使它是 where 子句的一部分。
  • 虽然我对 MySQL 不是很熟悉,但我对 SQL Server 了解得更多,并且对于 similar example on SQL Server,该索引仅在索引仅返回少数行时使用。即使只有 10 行,它仍然选择全表扫描而不是使用索引进行过滤,然后无论如何都必须查找主表数据。

标签: mysql


【解决方案1】:

MySQL(实际上是任何数据库)将使用索引来获取行,然后处理额外的where 条件(即anded in)。

如果organization_id 上没有索引,那么你不知道先执行哪个。许多数据库试图根据比较的复杂性来优化 where 条件,但这是基于内部指标,可能并不适用于所有情况。

【讨论】:

  • 很高兴知道...我认为这很可能是因为从优化的角度来看它是有意义的。根据我添加的解释屏幕截图,它似乎正在使用索引。我只是不知道它是在通配符搜索之前还是之后使用索引。
猜你喜欢
  • 1970-01-01
  • 2013-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-15
  • 1970-01-01
  • 2022-01-08
  • 2013-06-30
相关资源
最近更新 更多