一.唯一索引

唯一索引字面上理解就是在索引上增加唯一约束,不允许出现索引值相同的行,目前只有Btree索引可以声明唯一索引,唯一键会自动创建唯一索引。

测试表:

test=# create table tbl_unique_index(a int, b int);
CREATE TABLE

示例1.创建唯一索引,相等数据只允许插入一行,NULL除外,因为NULL不等于NULL。

test=# create unique index idx_unq_tbl_unique_index_a_b on tbl_unique_index using btree (a,b);
CREATE INDEX
test=# \d tbl_unique_index
Table "public.tbl_unique_index"
Column | Type | Modifiers
--------+---------+-----------
a | integer |
b | integer |
Indexes:
"idx_unq_tbl_unique_index_a_b" UNIQUE, btree (a, b)
test=# insert into tbl_unique_index values (1,1);
INSERT 0 1
test=# insert into tbl_unique_index values (1,1);
ERROR: duplicate key value violates unique constraint "idx_unq_tbl_unique_index_a_b"
DETAIL: Key (a, b)=(1, 1) already exists.
test=# insert into tbl_unique_index values (1);
INSERT 0 1
test=# insert into tbl_unique_index values (1);
INSERT 0 1
test=# insert into tbl_unique_index values (1);
INSERT 0 1

示例2.唯一键会自动创建唯一索引

test=# truncate table tbl_unique_index ;
TRUNCATE TABLE
test=# alter table tbl_unique_index add constraint pk_tbl_unique_index_a primary key(a);
ALTER TABLE
test=# alter table tbl_unique_index add constraint uk_tbl_unique_index_b unique(b);
ALTER TABLE
test=# \d tbl_unique_index
Table "public.tbl_unique_index"
Column | Type | Modifiers
--------+---------+-----------
a | integer | not null
b | integer |
Indexes:
"pk_tbl_unique_index_a" PRIMARY KEY, btree (a)
"idx_unq_tbl_unique_index_a_b" UNIQUE, btree (a, b)
"uk_tbl_unique_index_b" UNIQUE CONSTRAINT, btree (b)

二.表达式索引

除针对表的字段直接创建索引外,还可以对字段进行某种运算之后的结果创建索引。

测试表

test=# create table tbl_expression(a varchar(32), b varchar(32));
CREATE TABLE
test=# insert into tbl_expression select concat('test',x),concat('you',x) from generate_series(1,10000) x;
INSERT 0 10000

如果此时分别在a和b字段上各创建一个Btree索引,分别使用a和b字段查询时会进行索引扫描。

test=# create index idx_tbl_expression_a on tbl_expression using btree (a);
CREATE INDEX
test=# create index idx_tbl_expression_b on tbl_expression using btree (b);
CREATE INDEX
test=#
test=# explain analyze select * from tbl_expression where a = 'TEST';
QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------
-
Index Scan using idx_tbl_expression_a on tbl_expression (cost=0.29..8.30 rows=1 width=15) (actual time=0.130..0.130 rows=0 loops=1)
Index Cond: ((a)::text = 'TEST'::text)
Planning time: 0.667 ms
Execution time: 0.168 ms
(4 rows) test=# explain analyze select * from tbl_expression where b = 'you';
QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------
-
Index Scan using idx_tbl_expression_b on tbl_expression (cost=0.29..8.30 rows=1 width=15) (actual time=0.171..0.171 rows=0 loops=1)
Index Cond: ((b)::text = 'you'::text)
Planning time: 0.126 ms
Execution time: 0.206 ms
(4 rows)

但是下面的两种查询方式是不会进行索引扫描的

select * from tbl_expression where upper(a) = 'TEST';
select * from tbl_expression where (a || ' ' ||b) = 'test you';
test=# explain analyze select * from tbl_expression where upper(a) = 'TEST';
QUERY PLAN
------------------------------------------------------------------------------------------------------------
Seq Scan on tbl_expression (cost=0.00..166.00 rows=50 width=15) (actual time=5.957..5.957 rows=0 loops=1)
Filter: (upper((a)::text) = 'TEST'::text)
Rows Removed by Filter: 10000
Planning time: 0.140 ms
Execution time: 6.014 ms
(5 rows) test=#
test=# explain analyze select * from tbl_expression where (a || ' ' ||b) = 'test you';
QUERY PLAN
------------------------------------------------------------------------------------------------------------
Seq Scan on tbl_expression (cost=0.00..191.00 rows=50 width=15) (actual time=7.851..7.851 rows=0 loops=1)
Filter: ((((a)::text || ' '::text) || (b)::text) = 'test you'::text)
Rows Removed by Filter: 10000
Planning time: 0.114 ms
Execution time: 7.883 ms
(5 rows)

此时就可以使用表达式创建索引来解决此类全表扫描问题。

test=# explain analyze select * from tbl_expression where upper(a) = 'TEST';
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on tbl_expression (cost=4.67..21.42 rows=50 width=15) (actual time=0.133..0.133 rows=0 loops=1)
Recheck Cond: (upper((a)::text) = 'TEST'::text)
-> Bitmap Index Scan on idx_tbl_expression_upper_a (cost=0.00..4.66 rows=50 width=0) (actual time=0.129..0.129 rows=0 loops=1)
Index Cond: (upper((a)::text) = 'TEST'::text)
Planning time: 0.565 ms
Execution time: 0.175 ms
(6 rows)
test=# create index idx_tbl_expression_a_b on tbl_expression ((a||' '||b));
CREATE INDEX
test=# explain analyze select * from tbl_expression where (a || ' ' ||b) = 'test you';
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on tbl_expression (cost=4.67..21.55 rows=50 width=15) (actual time=0.130..0.130 rows=0 loops=1)
Recheck Cond: ((((a)::text || ' '::text) || (b)::text) = 'test you'::text)
-> Bitmap Index Scan on idx_tbl_expression_a_b (cost=0.00..4.66 rows=50 width=0) (actual time=0.128..0.128 rows=0 loops=1)
Index Cond: ((((a)::text || ' '::text) || (b)::text) = 'test you'::text)
Planning time: 0.582 ms
Execution time: 0.187 ms
(6 rows)

但是还是需要根据实际业务情况仔细评估后决定采用何种索引,因为并不是索引越多越好。

三.部分索引

只在自己感兴趣的那部分数据上创建索引,而不是对每一行数据都创建索引,此种方式创建索引就需要使用WHERE条件了。

创建两个完全相同的表比较部分索引和全索引的区别。

测试表

test=# create table tbl_partial_index(id bigint,alarm_time timestamp without time zone,level varchar(12),alarm_desc varchar(100));
CREATE TABLE
test=# create table tbl_partial_index1(id bigint,alarm_time timestamp without time zone,level varchar(12),alarm_desc varchar(100));
CREATE TABLE

写入完全相同的数据

test=# insert into tbl_partial_index(id,alarm_time,level,alarm_desc) 
select generate_series(1,9000000),clock_timestamp()::timestamp without time zone,'green','正常';
INSERT 0 9000000
test=# insert into tbl_partial_index(id,alarm_time,level,alarm_desc)
select generate_series(9000000,9000100),clock_timestamp()::timestamp without time zone,'red','攻击';
INSERT 0 101
test=#
test=#
test=# insert into tbl_partial_index1(id,alarm_time,level,alarm_desc)
select generate_series(1,9000000),clock_timestamp()::timestamp without time zone,'green','正常';
INSERT 0 9000000
test=# insert into tbl_partial_index1(id,alarm_time,level,alarm_desc)
select generate_series(9000000,9000100),clock_timestamp()::timestamp without time zone,'red','攻击';
INSERT 0 101

示例1.在tbl_partial_index表字段level上创建索引

test=# create index idx_tbl_partial_index_level on tbl_partial_index using btree (level);
CREATE INDEX
Time: 31407.356 ms
test=#
test=# explain analyze select * from tbl_partial_index where level = 'red';
QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------
-------------
Index Scan using idx_tbl_partial_index_level on tbl_partial_index (cost=0.43..4.45 rows=1 width=29) (actual time=0.069..0.087 rows=
101 loops=1)
Index Cond: ((level)::text = 'red'::text)
Planning time: 0.268 ms
Execution time: 0.124 ms
(4 rows) Time: 23.460 ms
test=# select relname,pg_size_pretty(pg_relation_size(oid)) from pg_class where relname='idx_tbl_partial_index_level';
relname | pg_size_pretty
-----------------------------+----------------
idx_tbl_partial_index_level | 191 MB
(1 row) Time: 71.799 ms

示例2.在tbl_partial_index1表字段level等于red的行上创建索引

test=# create index idx_tbl_partial_index1_level on tbl_partial_index1(level) where level = 'red';
CREATE INDEX
Time: 5558.905 ms
test=# explain analyze select * from tbl_partial_index1 where level = 'red';
QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------------
---------------
Index Scan using idx_tbl_partial_index1_level on tbl_partial_index1 (cost=0.14..4.16 rows=1 width=29) (actual time=0.051..0.082 row
s=101 loops=1)
Planning time: 18.922 ms
Execution time: 0.136 ms
(3 rows) Time: 19.929 ms
test=# select relname,pg_size_pretty(pg_relation_size(oid)) from pg_class where relname='idx_tbl_partial_index1_level';
relname | pg_size_pretty
------------------------------+----------------
idx_tbl_partial_index1_level | 64 kB
(1 row) Time: 0.950 ms

比较上面两个示例的结果可知,全表索引在耗时和大小方面要比部分索引消耗更多的资源,查询'red'的数据排除环境影响基本相同,数据量更大,'red'占比更小时性能可能会有明显差异,但是查询非'red'数据时全表索引会有明显的性能优势,因为部分索引并没有'green'数据的索引,走的是全表扫描。

综上,根据数据的使用方式创建不同的索引在性能上是有明显差异的。

postgresql----唯一索引,表达式索引,部分索引的更多相关文章

  1. 聚集索引、非聚集索引、聚集索引组织表、堆组织表、Mysql/PostgreSQL对比、联合主键/自增长、InnoDB/MyISAM(引擎方面另开一篇)

    参考了多篇文章,分别记录,如下. 下面是第一篇的总结 http://www.jb51.net/article/76007.htm: 在MySQL中,InnoDB引擎表是(聚集)索引组织表(cluste ...

  2. mysql索引之一:索引基础(B-Tree索引、哈希索引、聚簇索引、全文(Full-text)索引区别)(唯一索引、最左前缀索引、前缀索引、多列索引)

    没有索引时mysql是如何查询到数据的 索引对查询的速度有着至关重要的影响,理解索引也是进行数据库性能调优的起点.考虑如下情况,假设数据库中一个表有10^6条记录,DBMS的页面大小为4K,并存储10 ...

  3. PostgreSQL 11 新特性之覆盖索引(Covering Index)(转载)

    通常来说,索引可以用于提高查询的速度.通过索引,可以快速访问表中的指定数据,避免了表上的扫描.有时候,索引不仅仅能够用于定位表中的数据.某些查询可能只需要访问索引的数据,就能够获取所需要的结果,而不需 ...

  4. Mysql索引介绍及常见索引(主键索引、唯一索引、普通索引、全文索引、组合索引)的区别

    Mysql索引概念:说说Mysql索引,看到一个很少比如:索引就好比一本书的目录,它会让你更快的找到内容,显然目录(索引)并不是越多越好,假如这本书1000页,有500也是目录,它当然效率低,目录是要 ...

  5. SQL Server索引 - 聚集索引、非聚集索引、非聚集唯一索引 <第八篇>

    聚集索引.非聚集索引.非聚集唯一索引 我们都知道建立适当的索引能够提高查询速度,优化查询.先说明一下,无论是聚集索引还是非聚集索引都是B树结构. 聚集索引默认与主键相匹配,在设置主键时,SQL Ser ...

  6. MySQL5.7 虚拟列实现表达式或函数索引

    MySQL5.7 虚拟列实现表达式或函数索引 http://www.linuxidc.com/Linux/2015-11/125162.htm https://dev.mysql.com/doc/re ...

  7. SQL有三个类型的索引,唯一索引 不能有重复,但聚集索引,非聚集索引可以有重复

    重要: (1) SQL如果创建时候,不指定类型那么默认是非聚集索引 (2) 聚集索引和非聚集索引都可以有重复记录,唯一索引不能有重复记录. (3) 主键 默认是加了唯一约束的聚集索引,但是也可以在主键 ...

  8. SQL存储原理及聚集索引、非聚集索引、唯一索引、主键约束的关系(补)

    索引类型 1.          唯一索引:唯一索引不允许两行具有相同的索引值 2.          主键索引:为表定义一个主键将自动创建主键索引,主键索引是唯一索引的特殊类型.主键索引要求主键中的 ...

  9. Mysql使用Java UUID作为唯一值时使用前缀索引测试

    Mysql可以使用字符串前缀 作为索引 以节约空间. 下面我们以 Java的UUID 生成的 32位(移除UUID中的 中划线)字符串 来做一下 测试. 表结构: CREATE TABLE `test ...

  10. 认识SQLServer索引以及单列索引和多列索引的不同

     一.索引的概念 索引的用途:我们对数据查询及处理速度已成为衡量应用系统成败的标准,而采用索引来加快数据处理速度通常是最普遍采用的优化方法. 索引是什么:数据库中的索引类似于一本书的目录,在一本书中使 ...

随机推荐

  1. MySQL 常用语法 之 DISTINCT

    DISTINCT作用很简单就是去除重复行的数据. 具体看下面列子 表A数据[两条 nami 99] nameA   scoreA robin    98 nami    99 saber  98 lu ...

  2. e1084. 捕获错误和异常

    All errors and exceptions extend from Throwable. By catching Throwable, it is possible to handle all ...

  3. 调用ffmpeg库编译时出现common.h:175:47: error: 'UINT64_C' was not declared in this scope

    解决办法 出现错误:jni/ffmpeg/libavutil/common.h:175:47: error: 'UINT64_C' was not declared in this scope 解决: ...

  4. dos中执行cd命令切换不到对应的盘解决方法

    可以使用cd命令,不过需要加参数 /d,如: cd /d e:

  5. opengl的矩阵理解

    原文链接:http://blog.csdn.net/byhuang/article/details/1476199 矩阵真的是一个很神奇的数学工具, 虽然单纯从数学上看, 它并没有什么特别的意义, 但 ...

  6. openal 基础知识2

    三枚举扩展包(enumeration extension,“ALC_ENUMERATION_EXT”) 开发者可以通过这个extension得到一个字符串列表,区分不同的渲染/捕捉设备.OpenALr ...

  7. 怎么解决MathType希腊字母无法显示的问题

    MathType是一种常见的数学公式编辑软件,有些用户在编辑论文公式的时候发现,一些希腊字母在公式编辑器中无法打出来,上面显示一个“叉”号,面对这种MathType希腊字母无法显示的问题该如何解决呢? ...

  8. MVC源码

    http://aspnetwebstack.codeplex.com/ MVC源码

  9. swift--控件工厂类的实现

    控件工厂类,简而言之就是,减少代码的复用率,只在哪里用,然后在哪里调: 代码如下: import UIKit class ViewFactory: UIView,UITextFieldDelegate ...

  10. vue 组件库

    iView https://www.iviewui.com/ Radon UI https://luojilab.github.io/radon-ui/#!/ Element http://eleme ...