like百分号在前走不走索引

文章目录

模糊查询,前置百分号不走索引;后置百分号才会走索引这可能是大部分人都知道的常识

表: t_user 索引:idx_mobile

CREATE TABLE `t_user` (
  `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `NAME` varchar(64) DEFAULT NULL COMMENT '名字',
  `MOBILE` varchar(11) DEFAULT NULL COMMENT '手机号',
  PRIMARY KEY (`ID`),
  KEY `INDEX_MOBILE ` (`MOBILE`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';

DELIMITER $$
CREATE PROCEDURE populate_users(IN user_count int)
BEGIN
	DECLARE i int DEFAULT 0;
	DECLARE mobile varchar(64);
	WHILE i < user_count DO
		-- 生成随机手机号		
		SELECT concat('1', substring(cast(3 + 
			(rand() * 10) % 7 AS char(50)), 1, 1), right(left(trim(cast(rand() 
			AS char(50))), 11), 9)) INTO mobile;
		INSERT INTO t_user(NAME, MOBILE) VALUES (CONCAT('user', i), mobile);
	END
END$$
DELIMITER ;

CALL populate_users(150369);

首先看一下数据量,t_user有150369条数据

mysql> SELECT @@version;
+-----------+
| @@version |
+-----------+
| 8.0.26    |
+-----------+
1 row in set (0.00 sec)

mysql> SELECT count(*) FROM t_user;
+----------+
| count(*) |
+----------+
|   150369 |
+----------+
1 row in set (0.01 sec)

SELECT MOBILE FROM t_user WHERE MOBILE LIKE ‘%12’;

通过执行计划可以看出,实际上是走了索引的

mysql> EXPLAIN SELECT MOBILE FROM t_user WHERE MOBILE LIKE '%12';
+----+-------------+--------+------------+-------+---------------+--------------+---------+------+--------+----------+--------------------------+
| id | select_type | table  | partitions | type  | possible_keys | key          | key_len | ref  | rows   | filtered | Extra                    |
+----+-------------+--------+------------+-------+---------------+--------------+---------+------+--------+----------+--------------------------+
|  1 | SIMPLE      | t_user | NULL       | index | NULL          | INDEX_MOBILE | 36      | NULL | 133801 |    11.11 | Using where; Using index |
+----+-------------+--------+------------+-------+---------------+--------------+---------+------+--------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)

再看一下查同时查非索引字段的情况,是没走索引的。

mysql> EXPLAIN SELECT `NAME`, MOBILE FROM t_user WHERE MOBILE LIKE '%12';
+----+-------------+--------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| id | select_type | table  | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra       |
+----+-------------+--------+------------+------+---------------+------+---------+------+--------+----------+-------------+
|  1 | SIMPLE      | t_user | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 133801 |    11.11 | Using where |
+----+-------------+--------+------------+------+---------------+------+---------+------+--------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

从上面几次试验,可以得到一个结论:like查询百分号前置,并不是100%不会走索引。如果只select索引字段,或者select索引字段和主键,也会走索引的

SELECT MOBILE FROM t_user WHERE MOBILE LIKE ‘%12’; 为什么会走索引?

使用到了索引覆盖这个优化策略,扫描INDEX_MOBILE这个索引就可以获取查询结果。

通过EXPLAIN ANALYZE可以看到,过滤成本是13484.35,扫描了14865行,整张表的数据150369条,而符合条件的有1493条,也就是说为了找出这1493条数据,扫描了133801行,大约占全表的89%左右。虽然走了索引,但是几乎是全索引扫描

mysql> SELECT count(ID) FROM t_user WHERE MOBILE LIKE '%12';
+-----------+
| count(ID) |
+-----------+
|      1493 |
+-----------+
1 row in set (0.09 sec)

mysql> EXPLAIN ANALYZE SELECT MOBILE FROM t_user WHERE MOBILE LIKE '%12'\G;
*************************** 1. row ***************************
EXPLAIN: -> Filter: (t_user.MOBILE like '%12')  (cost=13484.35 rows=14865) (actual time=0.056..96.805 rows=1493 loops=1)
    -> Index scan on t_user using INDEX_MOBILE  (cost=13484.35 rows=133801) (actual time=0.045..42.458 rows=150369 loops=1)

1 row in set (0.09 sec)

这里是没有用到索引条件下推这个优化策略的,因为Extra列里没有出现Using index condition

SELECT NAME, MOBILE FROM t_user WHERE MOBILE LIKE '%12’这种情况没走是因为查了非索引字段,需要回表查询name字段值,如果使用INDEX_MOBILE索引,则要进行一次全索引扫描,同时还要进行一次聚簇索引扫描(即全表扫描),不如直接进行全表扫描

mysql> EXPLAIN ANALYZE SELECT `NAME`, MOBILE FROM t_user WHERE MOBILE LIKE '%12'\G;
*************************** 1. row ***************************
EXPLAIN: -> Filter: (t_user.MOBILE like '%12')  (cost=13484.35 rows=14865) (actual time=0.081..110.698 rows=1493 loops=1)
    -> Table scan on t_user  (cost=13484.35 rows=133801) (actual time=0.046..53.859 rows=150369 loops=1)

1 row in set (0.11 sec)

ERROR:
No query specified

总结:
like百分号在前不一定不走索引,使用索引覆盖的情况还是可能会走索引的

在PostgreSQL中,对于包含`LIKE`操作符的查询,尤其是当模式部分包含通配符(如百分号 `%`)时,标准B-tree索引可能无法高效地支持这种模式匹配。这是因为B-tree索引通常基于精确值查找,而不适用于模糊搜索。 然而,你可以尝试以下几种方法来改善`LIKE`查询的性能: 1. **索引** (Prefix Index): 如果模式总是以特定字符串开始,可以创建一个仅包含该缀的索引。例如,如果你经常查询`'%某种模式%'`,则可以创建一个索引在`某种模式`之,如`CREATE INDEX idx_name_prefix ON table (column(LENGTH('某种模式') + 1)) WHERE column LIKE '某种模式%'`。请注意,这种方法可能不适用于长度可变的模式。 2. **全文索引** (Full-text Search): PostgreSQL提供了一个名为`pg_trgm`模块的全文搜索功能,适合处理`LIKE`操作中的模糊匹配。你可以通过`gin_trgm_ops`扩展创建索引,并且`%`会被视为trigram的一部分。例如: ``` CREATE EXTENSION IF NOT EXISTS pg_trgm; CREATE INDEX idx_column_trgm ON table USING gin (column gin_trgm_ops); ``` 3. **位图索引** (Bitmap Index): 如果模式是固定的字符集合,可以考虑使用位图索引,虽然它不适合动态模式,但如果模式固定,可以帮助加速查询。但是,PostgreSQL的位图索引对于`LIKE`查询的支持有限,通常用于特定场景。 4. **定期运行自调整索引** (Auto Vacuum): 保持数据库的良好维护,包括定期运行`VACUUM`和`ANALYZE`命令,以便数据库能自动调整统计信息,提高查询计划的质量。 5. **查询改写** (Query Re-writing): 在某些情况下,你可以通过编写适当的存储过程或者应用程序逻辑来避免直接使用`LIKE`,而是利用更有效的查询结构。 记住,最佳索引选择取决于具体的业务需求和查询模式,所以你应该监控查询计划并评估实际效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值