SQL中的函数索引/表达式索引

SQL中的函数索引/表达式索引

在大多数数据库系统中,"函数索引"和"表达式索引"指的是同一个概念。它们都是指对一个表达式(而不仅仅是列名)的结果创建的索引。

下面我们以几个主流数据库为例来详细说明。


1. 什么是函数索引/表达式索引?

标准的索引是针对一个或多个列的原始值创建的。例如:

sql 复制代码
CREATE INDEX idx_employee_name ON employees (last_name);

这个索引 idx_employee_name 会存储 last_name 列的值,并快速定位到特定的姓氏。

函数索引(或表达式索引) 是针对一个表达式的结果创建的。这个表达式通常包含一个或多个列,并经过函数处理或计算。

例如,如果你想忽略大小写地搜索姓氏,可以创建一个这样的索引:

sql 复制代码
-- 在 PostgreSQL 中
CREATE INDEX idx_employee_name_lower ON employees (LOWER(last_name));

这个索引 idx_employee_name_lower 存储的不再是 'Smith',而是 'smith'。当你使用 LOWER(last_name) 进行查询时,数据库就可以利用这个索引。

2. 为什么需要它?(主要优点)

  1. 提升查询性能 :当你的 WHERE 子句、JOIN 条件或 ORDER BY 子句中使用了函数或表达式时,普通索引将无法被使用,导致全表扫描。函数索引可以让这类查询利用索引,大幅提高速度。
  2. 强制数据完整性:可以创建一个基于函数的唯一索引,来保证表达式级别的唯一性。例如,确保邮箱地址的小写形式是唯一的。

3. 如何使用?(语法示例)

不同的数据库系统语法略有不同,但核心思想一致。

PostgreSQL

PostgreSQL 官方文档中通常使用"表达式索引"这个术语。

sql 复制代码
-- 1. 不区分大小写的查询
CREATE INDEX idx_user_email_lower ON users (LOWER(email));
-- 查询时,这样就能用上索引
SELECT * FROM users WHERE LOWER(email) = LOWER('SomeOne@Example.COM');

-- 2. 对日期进行查询(例如,只按日期部分查询,忽略时间)
CREATE INDEX idx_orders_order_date ON orders (DATE(order_timestamp));
SELECT * FROM orders WHERE DATE(order_timestamp) = '2023-10-25';

-- 3. 对两个列进行计算后索引
CREATE INDEX idx_products_total_value ON products (unit_price * quantity_in_stock);
SELECT * FROM products WHERE (unit_price * quantity_in_stock) > 100;

-- 4. 创建唯一的表达式索引
CREATE UNIQUE INDEX idx_users_unique_username ON users (LOWER(username));
-- 这将阻止插入 'JohnDoe' 和 'johndoe',因为它们的 LOWER() 结果相同。
MySQL

MySQL 从 8.0.13 版本开始支持函数索引(在之前版本可以通过生成列来模拟)。

sql 复制代码
-- 1. 不区分大小写的索引
CREATE INDEX idx_employee_name_lower ON employees ((LOWER(last_name)));
-- 注意:MySQL 8.0.13+ 要求表达式用括号括起来

-- 2. 对日期部分创建索引
CREATE INDEX idx_sales_date ON sales ((DATE(sale_datetime)));

在 MySQL 5.7 及更早版本中的变通方法(使用生成列):

sql 复制代码
-- 先添加一个虚拟的生成列
ALTER TABLE employees
ADD COLUMN last_name_lower VARCHAR(100) AS (LOWER(last_name)) VIRTUAL;

-- 然后在这个生成列上创建普通索引
CREATE INDEX idx_employee_name_lower ON employees (last_name_lower);
Oracle

Oracle 也支持函数索引。

sql 复制代码
-- 1. 不区分大小写的索引
CREATE INDEX idx_emp_name_lower ON employees (LOWER(last_name));

-- 2. 使用函数创建唯一约束
CREATE UNIQUE INDEX idx_prod_code ON products (UPPER(product_code));

4. 注意事项和缺点

  1. 维护开销:和普通索引一样,函数索引会在插入、更新和删除数据时带来额外的开销,因为索引也需要被维护。
  2. 精确匹配 :查询必须精确地 使用索引定义中相同的表达式,优化器才能识别并使用它。
    • 能用上索引SELECT ... WHERE LOWER(name) = 'alice'
    • 用不上索引SELECT ... WHERE name = 'Alice' (即使 name'Alice',也不会使用 LOWER(name) 上的索引)
  3. 数据库支持:并非所有数据库都原生支持。请查阅您所用数据库的文档。
  4. 大小写敏感性 :索引表达式本身可能是大小写敏感的(例如,在 PostgreSQL 中 LOWER()UPPER() 是不同的)。确保你的查询和索引使用相同的函数。

总结

特性 普通索引 函数索引/表达式索引
索引内容 列的原始值 对列应用函数或计算后的结果
适用场景 WHERE column = 'value' WHERE FUNCTION(column) = 'value'
优点 结构简单,维护直接 极大优化了包含函数/表达式的查询
缺点 无法优化复杂条件的查询 维护成本稍高,查询必须精确匹配表达式

核心思想:如果你发现某些包含函数或表达式的查询速度很慢,并且这些查询频繁执行,那么为这些表达式创建一个函数索引是一个非常有效的优化手段。

相关推荐
武子康2 小时前
Java-166 Neo4j 安装与最小闭环 | 10 分钟跑通 + 远程访问 Docker neo4j.conf
java·数据库·sql·docker·系统架构·nosql·neo4j
S_h_a_2 小时前
八股-Mysql 基础篇(1)
数据库·mysql
Dxy12393102162 小时前
MySQL的GROUP_CONCAT函数详解
数据库·mysql
编啊编程啊程3 小时前
【029】智能停车计费系统
java·数据库·spring boot·spring·spring cloud·kafka
Leon-Ning Liu3 小时前
Oracle数据库常用视图:dba_datapump_jobs
数据库·oracle·dba
数据库生产实战4 小时前
Oracle 19C RAC下TRUNCATE TABLE的REUSE STORAGE选项作用和风险浅析!
数据库·oracle
小白银子4 小时前
零基础从头教学Linux(Day 60)
linux·数据库·mysql·oracle
瀚高PG实验室5 小时前
数据库安全配置指导
服务器·数据库·瀚高数据库
憋问我,我也不会5 小时前
MYSQL 命令
数据库·mysql