当前位置:   article > 正文

PostgreSql 唯一索引,表达式索引,部分索引_pgsql 修改唯一索引

pgsql 修改唯一索引

一.唯一索引

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

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

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

 

  1. test=# create unique index idx_unq_tbl_unique_index_a_b on tbl_unique_index using btree (a,b);
  2. CREATE INDEX
  3. test=# \d tbl_unique_index
  4. Table "public.tbl_unique_index"
  5. Column | Type | Modifiers
  6. --------+---------+-----------
  7. a | integer |
  8. b | integer |
  9. Indexes:
  10. "idx_unq_tbl_unique_index_a_b" UNIQUE, btree (a, b)

 

  1. test=# insert into tbl_unique_index values (1,1);
  2. INSERT 0 1
  3. test=# insert into tbl_unique_index values (1,1);
  4. ERROR: duplicate key value violates unique constraint "idx_unq_tbl_unique_index_a_b"
  5. DETAIL: Key (a, b)=(1, 1) already exists.
  6. test=# insert into tbl_unique_index values (1);
  7. INSERT 0 1
  8. test=# insert into tbl_unique_index values (1);
  9. INSERT 0 1
  10. test=# insert into tbl_unique_index values (1);
  11. INSERT 0 1

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

 

  1. test=# truncate table tbl_unique_index ;
  2. TRUNCATE TABLE
  3. test=# alter table tbl_unique_index add constraint pk_tbl_unique_index_a primary key(a);
  4. ALTER TABLE
  5. test=# alter table tbl_unique_index add constraint uk_tbl_unique_index_b unique(b);
  6. ALTER TABLE
  7. test=# \d tbl_unique_index
  8. Table "public.tbl_unique_index"
  9. Column | Type | Modifiers
  10. --------+---------+-----------
  11. a | integer | not null
  12. b | integer |
  13. Indexes:
  14. "pk_tbl_unique_index_a" PRIMARY KEY, btree (a)
  15. "idx_unq_tbl_unique_index_a_b" UNIQUE, btree (a, b)
  16. "uk_tbl_unique_index_b" UNIQUE CONSTRAINT, btree (b)

 

二.表达式索引

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

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

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

 

  1. test=# create index idx_tbl_expression_a on tbl_expression using btree (a);
  2. CREATE INDEX
  3. test=# create index idx_tbl_expression_b on tbl_expression using btree (b);
  4. CREATE INDEX
  5. test=#
  6. test=# explain analyze select * from tbl_expression where a = 'TEST';
  7. QUERY PLAN
  8. -------------------------------------------------------------------------------------------------------------------------------------
  9. -
  10. 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)
  11. Index Cond: ((a)::text = 'TEST'::text)
  12. Planning time: 0.667 ms
  13. Execution time: 0.168 ms
  14. (4 rows)
  15. test=# explain analyze select * from tbl_expression where b = 'you';
  16. QUERY PLAN
  17. -------------------------------------------------------------------------------------------------------------------------------------
  18. -
  19. 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)
  20. Index Cond: ((b)::text = 'you'::text)
  21. Planning time: 0.126 ms
  22. Execution time: 0.206 ms
  23. (4 rows)

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

  1. select * from tbl_expression where upper(a) = 'TEST';
  2. select * from tbl_expression where (a || ' ' ||b) = 'test you';
  3. test=# explain analyze select * from tbl_expression where upper(a) = 'TEST';
  4. QUERY PLAN
  5. ------------------------------------------------------------------------------------------------------------
  6. Seq Scan on tbl_expression (cost=0.00..166.00 rows=50 width=15) (actual time=5.957..5.957 rows=0 loops=1)
  7. Filter: (upper((a)::text) = 'TEST'::text)
  8. Rows Removed by Filter: 10000
  9. Planning time: 0.140 ms
  10. Execution time: 6.014 ms
  11. (5 rows)
  12. test=#
  13. test=# explain analyze select * from tbl_expression where (a || ' ' ||b) = 'test you';
  14. QUERY PLAN
  15. ------------------------------------------------------------------------------------------------------------
  16. Seq Scan on tbl_expression (cost=0.00..191.00 rows=50 width=15) (actual time=7.851..7.851 rows=0 loops=1)
  17. Filter: ((((a)::text || ' '::text) || (b)::text) = 'test you'::text)
  18. Rows Removed by Filter: 10000
  19. Planning time: 0.114 ms
  20. Execution time: 7.883 ms
  21. (5 rows)

 

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

 

  1. test=# explain analyze select * from tbl_expression where upper(a) = 'TEST';
  2. QUERY PLAN
  3. ------------------------------------------------------------------------------------------------------------------------------------
  4. 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)
  5. Recheck Cond: (upper((a)::text) = 'TEST'::text)
  6. -> 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)
  7. Index Cond: (upper((a)::text) = 'TEST'::text)
  8. Planning time: 0.565 ms
  9. Execution time: 0.175 ms
  10. (6 rows)

 

  1. test=# create index idx_tbl_expression_a_b on tbl_expression ((a||' '||b));
  2. CREATE INDEX
  3. test=# explain analyze select * from tbl_expression where (a || ' ' ||b) = 'test you';
  4. QUERY PLAN
  5. --------------------------------------------------------------------------------------------------------------------------------
  6. 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)
  7. Recheck Cond: ((((a)::text || ' '::text) || (b)::text) = 'test you'::text)
  8. -> 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)
  9. Index Cond: ((((a)::text || ' '::text) || (b)::text) = 'test you'::text)
  10. Planning time: 0.582 ms
  11. Execution time: 0.187 ms
  12. (6 rows)

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

三.部分索引

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

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

 

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

写入完全相同的数据

 

  1. test=# insert into tbl_partial_index(id,alarm_time,level,alarm_desc)
  2. select generate_series(1,9000000),clock_timestamp()::timestamp without time zone,'green','正常';
  3. INSERT 0 9000000
  4. test=# insert into tbl_partial_index(id,alarm_time,level,alarm_desc)
  5. select generate_series(9000000,9000100),clock_timestamp()::timestamp without time zone,'red','攻击';
  6. INSERT 0 101
  7. test=#
  8. test=#
  9. test=# insert into tbl_partial_index1(id,alarm_time,level,alarm_desc)
  10. select generate_series(1,9000000),clock_timestamp()::timestamp without time zone,'green','正常';
  11. INSERT 0 9000000
  12. test=# insert into tbl_partial_index1(id,alarm_time,level,alarm_desc)
  13. select generate_series(9000000,9000100),clock_timestamp()::timestamp without time zone,'red','攻击';
  14. INSERT 0 101

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

 

  1. test=# create index idx_tbl_partial_index_level on tbl_partial_index using btree (level);
  2. CREATE INDEX
  3. Time: 31407.356 ms
  4. test=#
  5. test=# explain analyze select * from tbl_partial_index where level = 'red';
  6. QUERY PLAN
  7. -------------------------------------------------------------------------------------------------------------------------------------
  8. -------------
  9. 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=
  10. 101 loops=1)
  11. Index Cond: ((level)::text = 'red'::text)
  12. Planning time: 0.268 ms
  13. Execution time: 0.124 ms
  14. (4 rows)
  15. Time: 23.460 ms

 

  1. test=# select relname,pg_size_pretty(pg_relation_size(oid)) from pg_class where relname='idx_tbl_partial_index_level';
  2. relname | pg_size_pretty
  3. -----------------------------+----------------
  4. idx_tbl_partial_index_level | 191 MB
  5. (1 row)
  6. Time: 71.799 ms

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

 

  1. test=# create index idx_tbl_partial_index1_level on tbl_partial_index1(level) where level = 'red';
  2. CREATE INDEX
  3. Time: 5558.905 ms
  4. test=# explain analyze select * from tbl_partial_index1 where level = 'red';
  5. QUERY PLAN
  6. -------------------------------------------------------------------------------------------------------------------------------------
  7. ---------------
  8. 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
  9. s=101 loops=1)
  10. Planning time: 18.922 ms
  11. Execution time: 0.136 ms
  12. (3 rows)
  13. Time: 19.929 ms
  14. test=# select relname,pg_size_pretty(pg_relation_size(oid)) from pg_class where relname='idx_tbl_partial_index1_level';
  15. relname | pg_size_pretty
  16. ------------------------------+----------------
  17. idx_tbl_partial_index1_level | 64 kB
  18. (1 row)
  19. Time: 0.950 ms

 

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/391217
推荐阅读
相关标签
  

闽ICP备14008679号