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