MySQL8.0 函数索引

MySQL8.0 函数索引

MySQL8.0.13 开始支持 在索引中使用函数的值

支持降序索引

支持JSON 数据的索引

函数索引基于虚拟列功能实现

创建表与索引

在 t3 表 上建立索引,创建普通索引和函数的索引

CREATE TABLE `t3` (
  `c1` varchar(10),
  `c2` varchar(10)
);


mysql> create index idx_c1 on t3(c1);
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0


-- 创建函数索引
mysql> create index idx_func_c2 on t3( (UPPER(c2)) );
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0
mysql> explain select * from t3 where upper(c1) = 'ABC' \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t3
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1
     filtered: 100.00
        Extra: Using where
1 row in set, 1 warning (0.00 sec)




mysql> explain select * from t3 where upper(c2) = 'ABC' \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t3
   partitions: NULL
         type: ref
possible_keys: idx_func_c2
          key: idx_func_c2
      key_len: 43
          ref: const
         rows: 1
     filtered: 100.00
        Extra: NULL
1 row in set, 1 warning (0.01 sec)

可以看到 c2 这个字段 会走 函数的索引

针对JSON数据 创建索引

json 数据创建索引

CAST(x AS type) 可以将一个数据类型 转化为另一个数据类型。 type 取值有 BINARY, CHAR(n), DATE,TIME, DATETIME,DEMICAL,SIGNED,UNSIGNED 等

mysql> select cast(1100 as char(2));
+-----------------------+
| cast(1100 as char(2)) |
+-----------------------+
| 11                    |
+-----------------------+
1 row in set, 1 warning (0.00 sec)

将 1100 数字 转为字符串类型,结果为 '11'

create table t4(data json, index((CAST(data ->> '$.name' as char(30) ) )));


mysql> show index from t4\G
*************************** 1. row ***************************
        Table: t4
   Non_unique: 1
     Key_name: functional_index
 Seq_in_index: 1
  Column_name: NULL
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment:
Index_comment:
      Visible: YES
   Expression: cast(json_unquote(json_extract(`data`,_latin1\'$.name\')) as char(30) charset latin1)
1 row in set (0.00 sec)
                                              

使用 explain 分析 是否可以使用索引.


mysql> explain select * from t4 where CAST(data ->> '$.name' as char(30)) = 'abc' \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t4
   partitions: NULL
         type: ref
possible_keys: functional_index
          key: functional_index
      key_len: 33
          ref: const
         rows: 1
     filtered: 100.00
        Extra: NULL
1 row in set, 1 warning (0.00 sec)

发现可以使用到索引

请添加图片描述

创建一个虚拟列

来给 t3 表 增加一列 ,增加一个虚拟计算列

mysql> alter table t3 add column c3 varchar(10) generated always as (upper(c1));

mysql> select * from t3;
Empty set (0.00 sec)

mysql> insert into t3(c1,c2) values('aa','frank');
Query OK, 1 row affected (0.01 sec)


mysql> select * from t3;
+------+-------+------+
| c1   | c2    | c3   |
+------+-------+------+
| aa   | frank | AA   |
+------+-------+------+
1 row in set (0.00 sec)

创建一个普通的索引 idx_c3

create index idx_c3 on t3(c3);
mysql> explain select * from t3 where c3='aa';
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key    | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | t3    | NULL       | ref  | idx_c3        | idx_c3 | 43      | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

此时可以发现就走索引了. 相当于是 建立了一个函数索引

explain select * from t3 where upper(c1)='AAA';

mysql> explain select * from t3 where upper(c1)='AAA';
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key    | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | t3    | NULL       | ref  | idx_c3        | idx_c3 | 43      | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+

小问题

有一个 员工表 , id, 奖金 , 薪水 三列, 表结构如下

create table employee(
	id int auto_increment primary key,
	salary int not null,
	bonus int not null
);

经常需要 按照 salary 加上 bonus 的和值 进行查询并且 排序显示,如何设计索引?

create index idx_func on employee((salary + bonus));

show index from employee \G

这样做 是可以使用索引的

mysql> explain select * from employee  where salary + bonus =100 \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: employee
   partitions: NULL
         type: ref
possible_keys: idx_func
          key: idx_func
      key_len: 8
          ref: const
         rows: 1
     filtered: 100.00
        Extra: NULL
1 row in set, 1 warning (0.00 sec)

官方文档例子

example1 指定索引表达式与JSON_UNQUOTE()相同的排序方式

Assign the indexed expression the same collation as JSON_UNQUOTE():

CREATE TABLE employees (
  data JSON,
  INDEX idx ((CAST(data->>"$.name" AS CHAR(30)) COLLATE utf8mb4_bin))
);

INSERT INTO employees VALUES
  ('{ "name": "james", "salary": 9000 }'),
  ('{ "name": "James", "salary": 10000 }'),
  ('{ "name": "Mary", "salary": 12000 }'),
  ('{ "name": "Peter", "salary": 8000 }');
  

SELECT * FROM employees WHERE data->>'$.name' = 'James';


explain SELECT * FROM employees WHERE data->>'$.name' = 'James';


请添加图片描述

The ->> operator is the same as JSON_UNQUOTE(JSON_EXTRACT(...)), and JSON_UNQUOTE() returns a string with collation utf8mb4_bin. The comparison is thus case-sensitive, and only one row matches:

example2 在查询中指定完整的表达式

CREATE TABLE employees (
  data JSON,
  INDEX idx ((CAST(data->>"$.name" AS CHAR(30))))
);


INSERT INTO employees VALUES
  ('{ "name": "james", "salary": 9000 }'),
  ('{ "name": "James", "salary": 10000 }'),
  ('{ "name": "Mary", "salary": 12000 }'),
  ('{ "name": "Peter", "salary": 8000 }');
  
explain SELECT * FROM employees WHERE CAST(data->>'$.name' AS CHAR(30)) = 'James';
 

请添加图片描述

SELECT * FROM employees WHERE CAST(data->>'$.name' AS CHAR(30)) = 'James';

CAST() returns a string with collation utf8mb4_0900_ai_ci, so the comparison case-insensitive and two rows match:

cast() 返回的 字符排序规则 是 utf8mb4_0900_ai_ci ,这个是大小写不敏感的,因此返回了两条数据。

+------------------------------------+
| data                               |
+------------------------------------+
| {"name": "james", "salary": 9000}  |
| {"name": "James", "salary": 10000} |
+------------------------------------+

总结

函数索引的功能 是MySQL8.0 以后才有的功能 ,如果有了这个特性,可以在使用函数的时候 使用这个索引啦,并且还支持JSON 的字段索引,是不是很方便呢?

参考文档

create-index-functional-key-parts

MySQL 8.0 新特性之函数索引

分享快乐,留住感动. '2022-10-16 19:55:36' --frank
### 关于MySQL 8.0中模糊查询及其索引优化 #### 模糊查询的基础概念 在MySQL中,模糊查询通常通过`LIKE`操作符实现。该操作符支持通配符 `%` 和 `_` 的使用,分别表示匹配零个或多个字符以及单个字符[^1]。 当涉及大量数据时,仅依赖 `LIKE '%value%'` 进行模糊查询可能会导致全表扫描,从而显著影响性能。因此,在设计数据库和编写查询语句时,应尽可能利用索引来提升查询效率。 --- #### 索引的选择与适用场景 ##### 单列索引 vs 联合索引 对于简单的模糊查询条件(如前缀匹配),可以通过创建普通的B树索引来加速查询过程。但如果查询涉及到多列组合,则推荐优先考虑 **联合索引** 来替代单独的单列索引[^3]。这是因为联合索引能够更高效地覆盖某些特定类型的查询需求,并减少因频繁回表带来的额外开销。 ```sql -- 创建联合索引示例 CREATE INDEX idx_name_age ON users(name, age); ``` 上述例子展示了基于两个字段构建的一个复合键结构;在这种情况下,“name”作为最左前列被定义出来之后紧接着才是“age”。这样做的好处在于允许我们针对这两个属性共同参与筛选逻辑的时候依旧保持较高的检索速度。 --- ##### 全文索引的应用 尽管常规 B 树索引适用于精确查找或者带有固定起始字符串模式(`LIKE 'prefix%'`)的情况,但对于任意位置内的子串搜索 (`LIKE '%substring%'`) 则显得力不从心。此时可引入另一种特殊形式——**全文索引**(Full-text Index),尤其适合处理自然语言文本资料的大规模相似度计算任务[^5]。 注意:只有 InnoDB 或 MyISAM 存储引擎才支持 FULLTEXT 类型声明方式;另外还需确保目标列的数据类型为 CHAR/VARCHAR/TEXT 中的一种才能成功应用此功能特性。 ```sql ALTER TABLE articles ADD FULLTEXT(title); SELECT * FROM articles WHERE MATCH (title) AGAINST ('database'); ``` 以上代码片段说明了如何向现有表格追加新的全文索引项并演示了一个基本的例子来展示其用法。这里的关键字函数MATCH()接受待检测的一组字段列表参数而AGAINST则指定要寻找的目标词条集合。 --- #### 查询计划工具 EXPLAIN 的作用 为了验证所建立的各种不同种类的辅助性机制是否真正发挥了预期效果,可以借助内置命令EXPLAIN获取详细的执行路径信息。这有助于开发者识别潜在瓶颈所在之处进而采取相应措施加以改进[^4]。 例如: ```sql EXPLAIN SELECT id FROM customers WHERE name LIKE 'John%'; ``` 这条指令返回的结果集中包含了诸如访问方法(access type), 所使用的具体索引名称(index used)以及其他重要统计指标等内容,便于后续深入剖析整个流程运作状况。 --- ### 总结 综上所述,在面对复杂的模糊查询请求时,合理规划相应的物理存储布局至关重要。除了传统的单一维度约束外,还应当积极探索其他高级选项比如全文搜索引擎等技术手段以满足日益增长的实际业务诉求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值