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'
优点 结构简单,维护直接 极大优化了包含函数/表达式的查询
缺点 无法优化复杂条件的查询 维护成本稍高,查询必须精确匹配表达式

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

相关推荐
updayday8545 小时前
电脑换了硬盘、加了内存,资产台账却没更新 - Ping64 硬件资产管理
大数据·网络·数据库·安全·智能路由器
hhhjhl6 小时前
mime-types 跨端三方库仓颉适配全流程
数据库
广州智造6 小时前
Radioss中破坏模型FAILTAB1的详细介绍
数据库·人工智能·算法·机器学习·仿真软件·radioss
李兆龙的博客6 小时前
从一到无穷大 #101:SSD 的工作原理——从 NAND 到数据库读写
数据库·ssd·存储
吹什么轩6 小时前
MySQL 内置函数全景:日期 / 字符串 / 数学 / 其他,一次讲透(附索引杀手排查)
java·数据库·面试
CS创新实验室6 小时前
改了模型,数据库为什么能自动跟上?——Django 迁移(migrations)的底层
数据库·django·sqlite
编码追梦人6 小时前
基于 ESP32-S3 的便携式多参数环境监护仪设计:从硬件选型到 FreeRTOS 多任务落地
数据库·单片机·嵌入式硬件·mongodb·esp32·freertos·低功耗设计
sunburn-6 小时前
数据库增删改查:从 SQL 基础到实践要点
java·数据库·mysql
誰能久伴不乏8 小时前
桌面客户端的运行日志系统:SQLite 分块 + 独立写线程 + 文本降级
数据库·c++·qt·架构·sqlite
2401_8967321315 小时前
MySQL小笔记
mysql