对部分行建立索引

背景:如果表中有一列的数据分布很不均匀,大部分是1,少部分是0,而且我们经常查询的刚好是0,在这种情况下,走全表扫描的话,有些浪费资源,如 果对该列建立索引的话,那些值为1的索引数据又有些浪费,因为我们很少去查询值为1的数据,所以我们只对值为0的数据建立索引。

 

 

Sql代码  收藏代码
  1. create table t6(status char(1));  
  2.   
  3. begin      
  4.   for i in 1..100000 loop  
  5.     insert into t6 values('1');  
  6.   end loop;  
  7.   for i in 1..10 loop  
  8.     insert into t6 values('0');  
  9.   end loop;  
  10. end;  

 对status列建立索引

 

Sql代码  收藏代码
  1. create index idx_t6_status on t6(status);  

 查询索引占用的块

 

Sql代码  收藏代码
  1. select index_name, i.leaf_blocks  
  2.   from user_indexes i  
  3.  where index_name = upper('idx_t6_status')  
Sql代码  收藏代码
  1. INDEX_NAME  LEAF_BLOCKS  
  2. X_T6_STATUS 182  
看到索引叶子块有182个,占用的比较多
 
下面我们只对status='0'建立索引来减少索引叶子块
Sql代码  收藏代码
  1. drop index idx_t6_status;  
  2.   
  3. create index idx_t6_status on t6(decode(status,'0','0'));  
  INDEX_NAME LEAF_BLOCKS
Sql代码  收藏代码
  1. 1   IDX_T6_STATUS   1  

 可以看到索引叶子块只有1个,数量减少了很多

 
通过索引查询status值为'0'的数据
Sql代码  收藏代码
  1. select * from t6 where decode(status, '0''0') = '0'  
 执行计划如下
Sql代码  收藏代码
  1. SELECT STATEMENT, GOAL = ALL_ROWS           2   29  87  
  2.  TABLE ACCESS BY INDEX ROWID    CARMOT_DEVELOP  T6  2   29  87  
  3.   INDEX RANGE SCAN  CARMOT_DEVELOP  IDX_T6_STATUS   1   389   
  转自:http://yufeng0471.iteye.com/blog/1059903
<think>我们正在讨论数据库索引的问题。问题:可不可以对空值建立索引? 回答:在大多数数据库管理系统中,是允许在包含NULL值的列上创建索引的,但是不同的数据库系统对NULL值的处理方式可能有所不同。 下面我将以几种常见的数据库系统为例进说明,并给出一些示例代码。 1. MySQL: 在MySQL中,可以在包含NULL值的列上创建索引。对于MyISAM和InnoDB存储引擎,NULL值被允许出现在索引列中,并且每个NULL值都被视为不同的值(除了唯一索引的特殊情况)。 但是,唯一索引(UNIQUE INDEX)在MySQL中允许包含多个NULL值,因为根据SQL标准,两个NULL值不被视为相等。 2. PostgreSQL: PostgreSQL同样允许在包含NULL值的列上创建索引。在唯一索引中,多个NULL值被认为是不冲突的,因为NULL表示未知的值,所以两个NULL值不被认为相等。 3. Oracle: Oracle也允许在包含NULL值的列上创建索引。但是,在Oracle中,索引不会存储完全为NULL的。也就是说,如果一索引列的值都为NULL,则该不会被索引(对于单列索引,该列NULL就不会被索引;对于复合索引,如果所有列都是NULL,则该不会被索引,但如果复合索引部分列有值、部分为NULL,则会被索引)。 4. SQL Server: 在SQL Server中,可以在包含NULL值的列上创建索引。唯一索引允许有一个NULL值(在SQL Server 2008及以后版本中,唯一索引允许多个NULL值,但这取决于ANSI_NULLS的设置,不过默认设置下,唯一索引允许多个NULL值)。 示例(以MySQL为例): 创建表时允许列可为NULL,并在该列上创建索引。 建表语句: ```sql CREATE TABLE example ( id INT AUTO_INCREMENT PRIMARY KEY, data VARCHAR(100), nullable_column VARCHAR(100) NULL ); ``` 在nullable_column列上创建普通索引: ```sql CREATE INDEX idx_nullable ON example (nullable_column); ``` 在nullable_column列上创建唯一索引(MySQL允许多个NULL值): ```sql CREATE UNIQUE INDEX idx_unique_nullable ON example (nullable_column); ``` 然后我们可以插入一些数据,包括多个NULL值: ```sql INSERT INTO example (data, nullable_column) VALUES ('first', NULL); INSERT INTO example (data, nullable_column) VALUES ('second', NULL); -- 对于唯一索引,这两个NULL值不会冲突 ``` 但是,如果尝试插入两个相同的非NULL值,唯一索引会阻止第二次插入: ```sql INSERT INTO example (data, nullable_column) VALUES ('third', 'non-null'); INSERT INTO example (data, nullable_column) VALUES ('fourth', 'non-null'); -- 这里会报错,违反了唯一约束 ``` 解释: 上面的代码展示了在MySQL中如何对允许NULL的列创建索引。普通索引和唯一索引都支持NULL值。在唯一索引中,多个NULL值是被允许的,因为NULL不等于任何值,包括NULL本身。 但是,需要注意的是,在某些数据库系统中,如果我们想要索引NULL值,可能需要特殊处理。例如,在Oracle中,如果我们想要索引完全为NULL的,可以使用基于函数的索引,例如使用NVL函数将NULL转换为一个特殊值。 另外,对于复合索引(多列索引),情况会更复杂一些。在复合索引中,如果所有列都是NULL,那么该不会被包含在索引中(在Oracle和SQL Server中都是如此)。因此,在查询条件中如果使用了复合索引,且条件中包含NULL,可能无法利用索引。 总结: 可以对包含NULL值的列建立索引,但是不同数据库系统对索引中的NULL值处理方式有所不同。在唯一索引中,通常允许多个NULL值存在;在复合索引中,如果所有列都为NULL,则该不会被索引。 因此,在设计数据库时,如果需要索引包含NULL的列,应当了解所使用数据库的具体为。 §§相关问题§§: 1. 在哪些情况下,数据库索引不会包含NULL值? 2. 如何在Oracle中索引包含NULL值的? 3. 在复合索引中,如果部分列为NULL,部分列为非NULL,该会被索引吗? 4. 在MySQL的InnoDB引擎中,唯一索引对NULL值是如何处理的? </think>### 能否对空值(NULL)建立索引? **答案:可以**,但具体为因数据库系统而异。以下是主流数据库的处理方式总结: | 数据库 | 普通索引 | 唯一索引 | NULL值是否参与索引 | |--------------|------------------------------|------------------------------|---------------------| | **MySQL** | ✅ 索引所有NULL值 | ✅ 允许多个NULL(视为不同值) | ✅ | | **PostgreSQL**| ✅ 索引所有NULL值 | ✅ 允许多个NULL | ✅ | | **Oracle** | ❌ 完全NULL索引(单列/复合) | ✅ 允许多个NULL | 部分索引 | | **SQL Server**| ✅ 索引所有NULL值 | ✅ 允许多个NULL | ✅ | --- ### 代码示例(MySQL) ```sql -- 创建包含NULL列的表 CREATE TABLE users ( id INT PRIMARY KEY, email VARCHAR(255) NULL ); -- 在可为NULL的列上创建普通索引 CREATE INDEX idx_email ON users(email); -- 创建唯一索引(允许多个NULL) CREATE UNIQUE INDEX uq_email ON users(email); -- 插入包含NULL的数据(合法) INSERT INTO users VALUES (1, 'user1@example.com'), (2, NULL), (3, NULL); -- 两个NULL被允许 ``` ### 关键解释 1. **普通索引** - NULL值会被包含在索引结构中 - 查询`WHERE email IS NULL`可以利用索引加速 2. **唯一索引** - 在MySQL/PostgreSQL中允许多个NULL(因为NULL≠NULL) - Oracle/SQL Server同样允许多个NULL值 - 非NULL值仍需保持唯一性 3. **Oracle的特殊为** - 完全为NULL的不会被索引(使用函数索引解决): ```sql CREATE INDEX idx_email_oracle ON users(NVL(email, 'EMPTY')); ``` --- ### 何时避免NULL索引? 1. **高频更新NULL列**:索引维护成本高 2. **超高NULL比例**(>30%):可能降低查询效率 3. **Oracle复合索引**:所有索引列全为NULL时不被索引 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值