CREATE INDEX 命令用于加速数据库查询,核心语法为:
CREATE [UNIQUE] INDEX 索引名 ON 表名 (列名1, 列名2, ...) [附加选项]
,其中索引名、表名和至少一个列名是必需的,UNIQUE 和附加选项可选。
在数据库管理中,索引(Index)是提升数据查询速度的关键机制,它类似于书籍的目录,允许数据库系统快速定位到表中的特定数据行,而无需逐行扫描整个表。CREATE INDEX
是 SQL 中用于在数据库表上创建新索引的标准命令。 理解其正确用法对于优化数据库性能至关重要。
最基本的 CREATE INDEX
语法结构如下:
CREATE INDEX index_name ON table_name (column_name1, column_name2, ...);
CREATE INDEX
: 这是创建索引的固定关键字。index_name
: 这是你为新索引指定的唯一名称,命名应具有描述性(idx_customer_lastname
),便于识别和管理。注意: 索引名在同一个表内必须唯一。ON table_name
: 指定要在哪个表上创建索引。table_name
是目标表的名称。(column_name1, column_name2, ...)
: 这是索引所基于的一个或多个列(称为索引键),列名放在括号内,用逗号分隔,索引将按照此处列出的列顺序存储数据(或数据的引用/指针),以便快速查找。
创建索引的详细步骤与示例
假设我们有一个 customers
表,包含以下列:customer_id
(主键), last_name
, first_name
, email
, city
。
-
创建单列索引:
如果我们经常需要根据last_name
来查找客户,可以创建一个单列索引:CREATE INDEX idx_customers_lastname ON customers (last_name);
执行此命令后,数据库会为
last_name
列创建一个索引结构(通常是 B-Tree 或其变种),当执行类似SELECT * FROM customers WHERE last_name = 'Smith';
的查询时,数据库可以利用这个索引快速找到所有姓氏为 ‘Smith’ 的记录,而无需扫描整个customers
表。 -
创建多列索引(复合索引):
如果我们经常需要根据last_name
和first_name
的组合来查询(查找 “John Smith”),创建一个复合索引会更高效:CREATE INDEX idx_customers_fullname ON customers (last_name, first_name);
- 列顺序很重要! 这个索引首先按
last_name
排序,在last_name
相同的情况下再按first_name
排序。 - 它对于以下查询非常有效:
WHERE last_name = 'Smith' AND first_name = 'John'
(最有效,使用了索引的所有部分)WHERE last_name = 'Smith'
(有效,使用了索引的第一部分)
- 但对于
WHERE first_name = 'John'
的查询,这个索引通常不会被使用,因为first_name
不是索引的最左列,这就是所谓的“最左前缀原则”。
- 列顺序很重要! 这个索引首先按
-
创建唯一索引 (
UNIQUE INDEX
):
唯一索引不仅加速查询,还强制索引键列(或列组合)的值在整个表中必须是唯一的,这常用于实现业务规则,如确保邮箱唯一。CREATE UNIQUE INDEX idx_customers_unique_email ON customers (email);
尝试插入或更新导致
email
列出现重复值的操作将会失败。 -
创建降序索引 (
DESC
):
默认情况下,索引按升序 (ASC
) 存储值,如果查询经常需要按某个列的降序获取结果(例如获取最新的订单),可以显式指定排序方式:CREATE INDEX idx_orders_orderdate_desc ON orders (order_date DESC);
对于
SELECT * FROM orders ORDER BY order_date DESC LIMIT 10;
这样的查询(获取最新的10个订单),降序索引可以避免数据库在返回结果前进行额外的排序操作。
创建索引的重要注意事项
-
权衡利弊:
- 利 (查询加速): 显著提高
SELECT
查询(特别是带有WHERE
,ORDER BY
,JOIN
子句的查询)的速度。 - 弊 (写操作开销): 索引需要维护,每次对表进行
INSERT
、UPDATE
或DELETE
操作时,相关的索引也需要更新,这会增加写操作的开销。过度创建索引会严重拖慢数据写入和修改的速度。 - 弊 (存储空间): 索引需要占用额外的磁盘空间。
- 利 (查询加速): 显著提高
-
明智选择索引列:
- 高选择性列优先: 选择包含大量不同值(唯一值比例高)的列创建索引效果最好(如
email
,user_id
),像gender
这样只有几个可能值的列(低选择性),索引效果通常很差,优化器可能直接忽略它进行全表扫描。 - WHERE 和 JOIN 子句中的列: 为经常出现在
WHERE
条件或JOIN ... ON ...
条件中的列创建索引。 - ORDER BY 和 GROUP BY 子句中的列: 为经常用于排序 (
ORDER BY
) 或分组 (GROUP BY
) 的列创建索引可以避免排序操作。 - 避免对频繁修改的小表建过多索引: 写开销可能得不偿失。
- 高选择性列优先: 选择包含大量不同值(唯一值比例高)的列创建索引效果最好(如
-
复合索引的列顺序:
- 遵循“最左前缀原则”,将查询条件中最常用、选择性最高的列放在复合索引的最左边。
- 考虑
ORDER BY
或GROUP BY
的需求,如果查询经常按(A, B)
排序,那么创建(A, B)
的索引通常比(B, A)
更优。
-
监控与维护:
- 不要一次性创建所有可能的索引: 根据实际查询负载(通过慢查询日志或数据库性能监控工具分析)逐步添加最有益的索引。
- 定期审查索引: 使用数据库提供的工具(如 MySQL 的
SHOW INDEX
,EXPLAIN
; PostgreSQL 的pg_stat_all_indexes
; SQL Server 的sys.dm_db_index_usage_stats
)分析索引的使用情况和效率,删除长时间未被使用或不再需要的冗余索引。 - 重建/重组索引: 随着数据的增删改,索引会产生碎片,降低效率,定期(或在性能下降时)根据数据库建议重建 (
REBUILD
) 或重组 (REORGANIZE
) 索引。
-
数据库系统差异:
- 虽然
CREATE INDEX
是标准 SQL,但不同数据库管理系统 (DBMS) 可能有特定的扩展、选项或限制:- MySQL / MariaDB: 支持
FULLTEXT
索引(全文搜索)、SPATIAL
索引(地理空间数据)。InnoDB
存储引擎支持聚簇索引(主键索引)。 - PostgreSQL: 支持多种索引类型(B-Tree, Hash, GiST, SP-GiST, GIN, BRIN),创建索引时可以指定
CONCURRENTLY
选项(允许在创建时不长时间阻塞表的写操作),支持表达式索引(CREATE INDEX idx ON tab ((lower(name)));
)。 - SQL Server: 支持
INCLUDE
子句将非键列包含在索引中(覆盖索引),支持筛选索引 (WHERE
条件),支持列存储索引(分析型查询)。CREATE INDEX
有ONLINE = ON
选项(类似 PostgreSQL 的CONCURRENTLY
)。 - Oracle: 支持丰富的索引类型(B-Tree, Bitmap, Function-Based, Domain, 等),有
ONLINE
选项。CREATE INDEX
语法也支持COMPUTE STATISTICS
在创建时收集统计信息。
- MySQL / MariaDB: 支持
- 务必查阅你所使用的具体数据库的官方文档,了解其
CREATE INDEX
语法的完整选项、限制和最佳实践。
- 虽然
何时使用 CREATE INDEX
- 当关键查询(尤其是频繁执行的或速度慢的查询)的
WHERE
、JOIN
、ORDER BY
、GROUP BY
子句涉及某些列时。 - 当需要强制列值的唯一性时(使用
UNIQUE INDEX
)。 - 当表数据量较大,且查询性能因全表扫描而下降时。
CREATE INDEX
是数据库性能调优的核心工具,通过为表的一个或多个列创建索引,可以极大提升数据检索速度,关键在于理解索引的工作原理、权衡其带来的查询加速与写操作开销、并基于实际的查询模式和数据特征来明智地选择和设计索引,避免盲目创建索引,定期监控和维护索引的健康状态,是确保数据库高效运行的重要环节,始终参考你所使用的特定数据库管理系统的官方文档以获取最准确和最新的信息。
主要参考来源:
- 关系型数据库管理系统 (RDBMS) 官方文档 (MySQL, PostgreSQL, SQL Server, Oracle 等) 中关于
CREATE INDEX
语句、索引类型、索引管理和性能优化的章节。 - 公认的数据库原理与性能优化权威书籍及在线资源。
原创文章,发布者:酷番叔,转转请注明出处:https://cloud.kd.cn/ask/4432.html