[Oracle][Postgresql][mysql]三个数据库产品下表字段存在空值或者为空创建索引是否生效测试

本文通过测试Oracle 11.2、PostgreSQL 10.11和MySQL的索引行为,探讨了在表字段存在空值或空字符串时,创建的索引是否在查询中生效。测试结果显示,MySQL和PostgreSQL在使用等于空字符串或IS NULL条件时可能走索引,而Oracle则不会。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*  ******************* postgresql 数据库测试开始   ***********************/
 

--本次测试以pg 数据库 10.11版本

postgres=# select version();
                           version
-------------------------------------------------------------
 PostgreSQL 10.11, compiled by Visual C++ build 1800, 64-bit
(1 行记录)


--创建一张测试表

create table t_index_null(id varchar(50),name text);

--造测试数据

insert into t_index_null(id,name)
select t.id,'test'||t.id::varchar
  from (select generate_series as id
          from generate_series(1,100000) ) as t;

--添加一条 id为null的数据  

insert into t_index_null(name) values ('zqw01');

--添加一条 id为空字符的数据  

insert into t_index_null(id,name) values ('','zqw02');

--对 id列 创建索引

create index idx_t_index_null_id on t_index_null(id);


--检锁id=1 的数据,看执行计划是否会走索引,走执行计划

explain analyze 
select id,name
  from t_index_null 
 where id = '1';

                                                            QUERY PLAN
-------------------------------------------------------------------------------------------
 Index Scan using idx_t_index_null_id on t_index_null  (cost=0.29..8.31 rows=1 width=14) (actual time=0.061..0.062 rows=1 loops=1)
   Index Cond: ((id)::text = '1'::text)
 Planning time: 0.289 ms
 Execution time: 0.086 ms
(4 行记录)

 
--检锁id='' (空字符) 的数据,看执行计划是否会走索引,走执行计划

explain analyze 
select id,name
  from t_index_null 
 where id = '';

                                                             QUERY PLAN
-------------------------------------------------------------------------------------------
 Index Scan using idx_t_index_null_id on t_index_null  (cost=0.29..8.31 rows=1 width=14) (actual time=0.050..0.052 rows=1 loops=1)
   Index Cond: ((id)::text = ''::text)
 Planning time: 0.114 ms
 Execution time: 0.078 ms
(4 行记录)


--检锁id is null (空字符) 的数据,看执行计划是否会走索引,走执行计划

explain analyze 
select id,name
  from t_index_null 
 where id is null;
<think>嗯,用户问的是单列索引和唯一索引的区别,这属于数据库索引的基础知识。从引用内容看,用户可能刚接触数据库优化,需要清晰的概念区分。 单列索引和唯一索引其实是两个维度的分类:单列索引是按索引列数划分的类型(对应复合索引),唯一索引是按约束性划分的类型(对应普通索引)。用户可能混淆了分类维度,需要先帮ta理清这个逻辑框架。 从引用[1]提取的核心区别点有三个:唯一性约束、空值处理和数量限制。唯一索引的“唯一性”是重点,这仅是性能优化手段,更是数据完整性的保障。比如用户手机号字段,用唯一索引能防止重复注册,普通索引就做到这点。 引用[2]补充了使用场景的差异。注意到用户提到“哪些查询条件会使用索引”,这提示我需要强调索引生效条件。比如带NULL的查询在唯一索引中可能全表扫描,而单列普通索引对NULL检索更友好。 用户没有说明具体数据库类型,但引用中出现了MySQL和分布式数据库案例。保险起见,我避免使用特定数据库的语法细节,比如Oracle的位图索引展开。最后用用户注册的案例说明实际应用差异,这样更直观。 要要补充索引维护成本呢?考虑到用户问题聚焦在“区别”,且引用材料未涉及存储细节,决定先扩展B+树结构这些底层内容。但准备在相关问题里放一个索引维护的选项,万一用户想深入呢。</think>以下是数据库中单列索引与唯一索引的核心区别总结: | **特性** | **单列索引** | **唯一索引** | |------------------|----------------------------------|----------------------------------| | **核心作用** | 加速查询(无约束) | 加速查询 + 数据唯一性约束 | | **重复** | ✅ 允许重复 | ❌ 禁止重复 | | **空值处理** | ✅ 允许多个NULL(视数据库而定) | ✅ 允许单个NULL(唯一性约束) | | **索引数量** | 单表可创建多个 | 单表可创建多个 | | **数据约束** | 无 | 强制唯一性(插入/更新时校验) | | **适用场景** | 频繁查询但允许重复的字段(如性别) | 需唯一性的字段(如身份证号、邮箱) | ### 详细解析 1. **功能目标同** - **单列索引**:仅用于加速对单个列的查询(如 `WHERE name = '张三'`)[^1] - **唯一索引**:在加速查询的同时,**强制保证该列数据的唯一性**(如防止重复身份证号入库)[^1] 2. **数据约束差异** - 唯一索引在插入/更新数据时会校验唯一性: ```sql -- 创建唯一索引后,重复操作将报错 CREATE UNIQUE INDEX idx_email ON users(email); INSERT INTO users(email) VALUES ('[email protected]'); -- 成功 INSERT INTO users(email) VALUES ('[email protected]'); -- 报错:Duplicate entry ``` - 单列索引无此限制,仅用于查询加速 3. **空值(NULL)处理** - 唯一索引允许存在 **单个NULL**(多数数据库MySQLPostgreSQL) *例:`email` 字段唯一索引中,`NULL, NULL, '[email protected]'` 合法* - 单列索引允许多个NULL(无约束) 4. **性能影响** - **写入性能**:唯一索引因需校验唯一性,写入速度略低于单列索引 - **查询性能**:二者在等查询(`=`)时效率相同,但唯一索引可利用唯一性做优化 ### 应用场景对比 | **场景** | **推荐索引类型** | **原因** | |------------------------|------------------|----------------------------------| | 用户注册邮箱字段 | 唯一索引 | 防止重复注册 | | 商品分类ID查询 | 单列索引 | 允许重复,仅需加速查询 | | 身份证号存储 | 唯一索引 | 确保每人唯一标识 | | 日志表中的IP地址查询 | 单列索引 | IP可重复,无需唯一约束 | ### 高级特性 - **覆盖索引优化**:若查询只需返回索引列,二者均可直接返回数据,避免回表[^2] ```sql -- 索引 idx_email (email) 覆盖查询 SELECT email FROM users WHERE email = '[email protected]'; ``` - **复合索引中的唯一性**:唯一索引可跨多列(如 `UNIQUE(name, birth)` 防止同名同生日重复) > **关键结论**:选择依据取决于是否需要强制数据唯一性。若需防重复(如业务主键),用唯一索引;若仅加速查询且允许重复,用单列索引。 --- **相关问题** 1. 唯一索引允许空值(NULL)吗?数据库的处理差异是什么? 2. 在已存在重复数据的字段创建唯一索引会怎样?如何安全操作? 3. 复合唯一索引与单列唯一索引的应用场景有何同? 4. 频繁更新的字段适合创建唯一索引吗?会引发什么性能问题? 5. 主键索引和唯一索引在功能上有何异同? [^1]: 主键索引和唯一索引均具有唯一性约束,但主键索引允许NULL且每表仅有一个 [^2]: 覆盖索引可显著减少I/O操作,尤其对高频查询字段
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值