Unique Index,唯一性索引,相信each of us都知道是怎么一回事。相对于普通的index,唯一性索引多了一个检查唯一性的checking。但,你对这个Unique Index是不是真的已经非常了解了?是吗?
1. 假设有以下表结构:
create temp table tmp_one (tid integer, tname char(12));
create temp table tmp_two (tid integer, tno integer, tname char(12));
create unique index tmp_one_idx on tmp_one(tid);
create unique index tmp_two_idx on tmp_two(tid, tno);
你觉得下面的代码执行结果是怎么样?
-- first
insert into tmp_one values (1, 'a');
insert into tmp_one values (2, 'b');
insert into tmp_one values (2, 'c');
insert into tmp_one values (null, 'd');
insert into tmp_one values (null, 'e');
-- second
insert into tmp_two values (1, 1, 'a');
insert into tmp_two values (2, 1, 'b');
insert into tmp_two values (2, 1, 'c');
insert into tmp_two values (null, 1, 'd');
insert into tmp_two values (null, 1, 'e');
insert into tmp_two values (null, null, 'f');
insert into tmp_two values (null, null, 'g');
-- finally query
select * from tmp_one order by tid;
select * from tmp_two order by tid, tno;
你觉得这个结果在Informix、MySQL、Oracle、PostgreSQL是否会一样呢?你觉得为什么会有这样的不同?
2. 有以下一个business表
create table business (
tid integer,
tkind char(1),
tname char(12)
);
现在有这样一个需求,对于所有tkind = ‘Y’的数据,tid都必须是唯一的,其余的tkind != ‘Y’ 或者null的数据不受这个限制。请问你会如何建这个“部分唯一性”的索引?
3. 假若存在一个表,
create table thing (
tid integer,
handled char(1), --这个标志位表示是否已经被day-end处理过,Y或者N
data char(300)
);
create unique index thing_idx on thing(tid);
假若thing表有1000w数据,handled列都是“Y”,然后每天会有一些front-end插入一些handled = ‘N’的记录(数量大概几百条的样子),接着每天晚上会有一个day-end把这些handled = ‘N’的数据取出来,处理完后,最后会把这些记录的handled update成“Y”。
--伪代码
for row in (select * from thing where handled = 'N' for update)
begin
-- 这里我省略了处理这条row的代码
update thing set handled = 'Y' where in current row
end
你会怎样改善这个过程?
1. NULL在索引的问题
这个NULL的问题在不同的数据库表现很不一样,informix把它看作一个普通的值;但在Oracle、MySQL、PostgreSQL中的情况完全相反——NULL不起作用。不过要留意,这里的“不起作用”还是有异同的。
简单来说,好像按照SQL标准(不知道是SQL92还是SQL99了),不应该对null进行索引,in other word,索引中不应该包含null,(注意,虽然我给出的例子是unique index,但普通索引也一样成立的,只不过unique index比较容易看到实验效果)
先列出Informix的结果:
下面是MySQL的结果:
然后是pgsql的结果:
最后是oracle的结果:
从上面的结果我们可以得到很多很多的信息。
大家可以看到,在这一方面pgsql竟然“背叛”了oralce,跟MySQL相同。
我不知道大家有没有留意,反正我是在写这篇文章的时候才留意到,这四个数据库对于NULL排序是有不同的。
在ASC升序的情况下,
Informix、MySQL是把NULL放在前面;pgsql和oracle把NULL放在最后。
相信在DESC降序时,情况会是倒过来的。
这个测试说明了:
- 不同的数据有不少关键地方是不同的,平时要多加笔;
- 对于unique index,如果业务允许,尽量增加not null的约束。
虽然几个数据库对NULL在索引上的表现有所不同,但Informix似乎是“独占鳌头”了,尽管我不怎么想说Informix烂
2.NULL在索引中的妙用
对于“部分唯一性”的约束,可能有人建议trigger。但实际情况下会有很多很多很多的问题。
首先是性能的问题,trigger绝对是性能杀手的重要一员,一个不留神就会中招。
其次是隔离级别的问题,不同隔离级别下看到的数据是不一样的,例如对于informix,如果别人的数据还没有commit,我们在read uncommitted下是可以得到的,但在其余的隔离级别是看不到的。这种“多样性”会导致很多判断上的分歧,令我们的系统存在不少“隐患”。
最后,我有点怀疑是否真的能够实现。因为数据库存在并发,我们当然需要对数据加锁,但一般数据库都没有类似MySQL(InnoDB)的“间隙锁”,似乎很难对不存在的数据进行加锁,即使是MySQL(InnoDB),间隙锁也必须是在repeatable read和serializable才有效,有一定的局限性。
实际上我们可以利用NULL不索引这个特性建立“部分唯一性”索引(或者叫有选择性的索引、有条件的索引)。
首先我们建一个function(这里以oracle为例)。可能很多人都不知道现在的数据库都可以create function的,实际上function跟procedure存储过程很相似,只是function必须有返回值。这个函数很简单,对于tkind = Y,返回实际的id,否则统统返回null。
create function test_fn1 (f_id in integer, f_kind in char(1)) return integer
deterministic
as
begin
if f_kind = 'Y' then
return f_id
end if
return null
end;
/
然后对表business建一个function index(函数索引)。要了解更多关于函数索引可以google一下。
create unique index busi_idx1 on business (test_fn1(tid, tkind));
这个时候已经可以实现部分唯一性约束了。因为这个函数只会对tkind = ‘Y’的数据返回真正的tid,其余的tkind都是返回null,所以我们的索引也就只对tkind = Y起作用了。我们知道null是不进入索引的。
注意:由于informix对null也会收录到index,所以这个方法对于Informix无效。如果你问我infomix下怎么搞,我answer:不知道。
3. 附加练习题
这一道附加题我就不打算细说了,看完上面估计大家都应该知道怎么做。
- 大小: 4.8 KB
- 大小: 3.1 KB
- 大小: 4 KB
- 大小: 4.1 KB
- 大小: 3.3 KB
- 大小: 59.4 KB
分享到:
相关推荐
数据库原理————1.ppt,西南交大……资料
一、SQL 增删改语句 二、SQL 查询语句 三、视图 四、索引 五、约束 六、触发器 七、存储过程 八、事务 九、函数
mysql主键和唯一索引的区别(csdn)————程序
python、numpy、Pytorch中的索引方式(csdn)————程序
1.3.2.InnoDB磁盘结构——索引.md 1.3.3.InnoDB磁盘结构——表空间.md 1.4.0.Mysql文件——参数文件.md 1.4.1.0.Mysql文件——日志文件.md 1.4.2.Mysql文件——socket文件.md 1.4.3.Mysql文件——pid文件.md 1.4.4.0...
牛逼!MySQL 8.0 中的索引可以隐藏了…(csdn)————程序
下列定义中,凡引入字母索引中的术语都用半黑体字印刷,在每个术语的定义中所引用到的其他术语都列出了它们所在编号。 给出编号的术语和定义按以下主题分类: ——通用术语 ——与质量有关的术语 ——与质量...
Python——torch.gather 的用法1 含义2 举例 1 含义 torch.gather(input, dim, index, out=None) → Tensor 定义:沿给定轴dim,将输入input中索引张量index指定位置的值进行聚合。 (1) input代表要处理的张量。 ...
安卓Android源码——按字母索引滑动.zip
安卓Andriod源码——按字母索引滑动.zip
安卓Android源码——按字母索引滑动.rar
UNIQUE:表示创建的是唯一性索引 FULLTEXT:表示创建全文索引; CREATE INDEX 语句并不能创建主键索引。 创建索引 CREATE [UNIQUE | FULLTEXT] INDEX 索引名 ON 表名(列名[(长度)] [ASC | DESC],...) 说明: 索引名:...
HASH 索引——用C语言实现,让你充分了解DBMS中索引的实现
近现代临床医学研究指南索引——量子医学暨大数据深度学习和探讨.pdf
Android源码——联系人快速索引源码.zip
13.sql.server.2005.索引 13.sql.server.2005.索引
——Ve.3.5.3 更新说明—— 1、修复了一个导致程序崩溃的BUG。 由Boier反馈。 ——Ve.3.5.2 更新说明—— 1、增加了TXT文章的导入导出功能,将TXT文章按字符切为节点。 ——Ve.3.5.1 更新说明—— 1、修复了一些...