postgresql 索引状态_postgresql----索引失效

本文探讨了PostgreSQL中导致索引失效的各种情况,包括:1) 使用计算、函数或类型转换;2) 不等于操作符(!=);3) 使用NOT;4) 模糊查询通配符在前;5) 索引字段在表中占比高;6) 多字段索引查询条件不包含第一列;7) 多字段索引查询条件使用OR。通过示例展示了解决这些问题的方法,如创建表达式索引。对于!=操作符、NOT以及NOT IN和NOT EXISTS的比较,也揭示了索引使用上的差异。

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

什么是索引失效?如果where过滤条件设置不合理,即使索引存在,且where过滤条件中包含索引列,也会导致全表扫描,索引不起作用。什么条件下会导致索引失效呢?

1.任何计算、函数、类型转换

2.!=

3.NOT,相当于使用函数

4.模糊查询通配符在开头

5.索引字段在表中占比较高

6.多字段btree索引查询条件不包含第一列

7.多字段索引查询条件使用OR(有时也会走索引扫描,但查询效率不高)

测试表

test=# \timing

Timingis on.

test=# create table tbl_index(a bigint,b timestamp without time zone ,c varchar(12));CREATE TABLETime:147.366ms

test=# insert into tbl_index select generate_series(1,10000000),clock_timestamp()::timestamp without time zone,'bit me';INSERT 0 10000000Time:30982.723 ms

1.任何计算、函数、类型转换

crtest=# create index idx_tbl_index_a ontbl_index (a);CREATE INDEXTime:19634.874ms

test=#

test=# explain analyze select * from tbl_index where a = 1;

QUERYPLAN

------------------------------------------------------------------------------------------------------------------------------

Index Scan using idx_tbl_index_a on tbl_index (cost=0.43..8.45 rows=1 width=23) (actual time=59.844..59.850 rows=1 loops=1)Index Cond: (a = 1)

Planning time:22.788ms

Execution time:60.011ms

(4rows)

Time:84.865ms

test=# explain analyze select * from tbl_index where a + 1 = 1;

QUERYPLAN

---------------------------------------------------------------------------------------------------------------------------------

Gather (cost=1000.00..84399.00 rows=50000 width=23) (actual time=7678.109..7678.109 rows=0 loops=1)

Workers Planned:2Workers Launched:2

-> Parallel Seq Scan on tbl_index (cost=0.00..78607.33 rows=20833 width=23) (actual time=7350.047..7350.047 rows=0 loops=3)

Filter: ((a+ 1) = 1)

Rows Removedby Filter: 3333333Planning time:0.112ms

Execution time:7688.615ms

(8rows)

Time:7780.024ms

test=# explain analyze select * from tbl_index where power(a,2) = 1;

QUERYPLAN

---------------------------------------------------------------------------------------------------------------------------------

Gather (cost=1000.00..94815.67 rows=50000 width=23) (actual time=47.516..6902.399 rows=1 loops=1)

Workers Planned:2Workers Launched:2

-> Parallel Seq Scan on tbl_index (cost=0.00..89024.00 rows=20833 width=23) (actual time=4607.894..6892.174 rows=0 loops=3)

Filter: (power((a)::double precision, '2'::double precision) = '1'::double precision)

Rows Removedby Filter: 3333333Planning time:13.564ms

Execution time:6904.232ms

(8rows)

Time:7051.482ms

test=#

test=# explain analyze select * from tbl_index where a::varchar = '1';

QUERYPLAN

---------------------------------------------------------------------------------------------------------------------------------

Gather (cost=1000.00..94815.67 rows=50000 width=23) (actual time=1.239..6689.272 rows=1 loops=1)

Workers Planned:2Workers Launched:2

-> Parallel Seq Scan on tbl_index (cost=0.00..89024.00 rows=20833 width=23) (actual time=4449.890..6679.233 rows=0 loops=3)

Filter: (((a)::character varying)::text = '1'::text)

Rows Removedby Filter: 3333333Planning time:1.029ms

Execution time:6692.329ms

(8rows)

Time:6723.530 ms

在表tbl_index.a字段创建btree索引,使用a=1索引生效,但是下面的例子运算、函数、类型转换却导致索引失效了。

where a + 1 = 1

where power(a,2) = 1

where a::varchar = '1'

如何解决呢?可参考前面的表达式索引解决:

create index idx_tbl_index_a on tbl_index ((a+1));

create index idx_tbl_index_a on tbl_index ((power(a,2)));

create index idx_tbl_index_a on tbl_index ((a::varchar));

2.!=

test=# explain analyze select * from tbl_index where a != 1;

QUERYPLAN

-------------------------------------------------------------------------------------------------------------------------

Seq Scan on tbl_index (cost=0.00..140899.00 rows=9999999 width=23) (actual time=0.049..11004.864 rows=9999999 loops=1)

Filter: (a<> 1)

Rows Removedby Filter: 1Planning time:0.206ms

Execution time:11585.859ms

(5rows)

Time:11587.146 ms

3.NOT,相当于使用函数

test=# explain analyze select * from tbl_index where a is null;

QUERYPLAN

------------------------------------------------------------------------------------------------------------------------------

Index Scan using idx_tbl_index_a on tbl_index (cost=0.43..4.45 rows=1 width=23) (actual time=30.092..30.092 rows=0 loops=1)Index Cond: (a IS NULL)

Planning time:33.783ms

Execution time:41.838ms

(4rows)

Time:102.544ms

test=# explain analyze select * from tbl_index where a is not null;

QUERYPLAN

--------------------------------------------------------------------------------------------------------------------------

Seq Scan on tbl_index (cost=0.00..115899.00 rows=10000000 width=23) (actual time=3.062..6309.908 rows=10000000 loops=1)

Filter: (aIS NOT NULL)

Planning time:0.099ms

Execution time:6877.566ms

(4rows)

Time:6878.156 ms

以上比较可知where a is null索引生效,但是where a is not null导致索引生效。类似导致索引失效的还有NOT IN,NOT LIKE等,但是NOT EXISTS不会导致索引失效。下面的例子可以看到tbl_index表仍进行索引扫描,但是性能仍有限制,使用NOT IN虽然索引失效,但性能比NOT EXISTS要高。这个和我之前的认识有些出入,之前测试发现NOT EXISTS比NOT IN性能高,看来情况不同,性能也是不一定的。

test=# explain analyze select * from tbl_index where a not in (select a fromtbl_test );

QUERYPLAN

-------------------------------------------------------------------------------------------------------------------------

Seq Scan on tbl_index (cost=14.50..140913.50 rows=5000000 width=23) (actual time=1.393..3717.312 rows=9999000 loops=1)

Filter: (NOT (hashed SubPlan 1))

Rows Removedby Filter: 1000SubPlan1

-> Seq Scan on tbl_test (cost=0.00..12.00 rows=1000 width=8) (actual time=0.038..0.236 rows=1000 loops=1)

Planning time:0.134ms

Execution time:4147.857ms

(7rows)

Time:4148.615ms

test=# explain analyze select * from tbl_index where not exists (select null from tbl_test where tbl_test.a =tbl_index.a);

QUERYPLAN

---------------------------------------------------------------------------------------------------------------------------------------------------------

Merge Anti Join (cost=62.45..218187.26 rows=9999000 width=23) (actual time=1.698..16909.581 rows=9999000 loops=1)

Merge Cond: (tbl_index.a=tbl_test.a)-> Index Scan using idx_tbl_index_a on tbl_index (cost=0.43..193110.43 rows=10000000 width=23) (actual time=0.035..14781.400row

s=10000000 loops=1)-> Sort (cost=61.83..64.33 rows=1000 width=8) (actual time=0.390..0.659 rows=1000 loops=1)

SortKey: tbl_test.a

Sort Method: quicksort Memory: 71kB-> Seq Scan on tbl_test (cost=0.00..12.00 rows=1000 width=8) (actual time=0.038..0.194 rows=1000 loops=1)

Planning time:0.339ms

Execution time:17530.472ms

(9rows)

Time:17594.258 ms

4.模糊查询通配符在开头

test=# explain analyze select * from tbl_index where c like 'bit%';

QUERYPLAN

--------------------------------------------------------------------------------------------------------------------------

Seq Scan on tbl_index (cost=0.00..140899.00 rows=10000000 width=23) (actual time=0.099..1685.317 rows=10000000 loops=1)

Filter: ((c)::text ~~ 'bit%'::text)

Planning time:55.373ms

Execution time:2104.863ms

(4rows)

Time:2164.464ms

test=# explain analyze select * from tbl_index where c like '%me';

QUERYPLAN

---------------------------------------------------------------------------------------------------------------------------

Seq Scan on tbl_index (cost=0.00..140899.00 rows=10000000 width=23) (actual time=20.172..5507.741 rows=10000000 loops=1)

Filter: ((c)::text ~~ '%me'::text)

Planning time:65.603ms

Execution time:6007.367ms

(4 rows)

5.索引字段在表中占比较高

test=# insert into tbl_index values (10000001,'2015-05-23 00:00:00','haha');INSERT 0 1Time:88.226ms

test=# explain analyze select * from tbl_index where c = 'bit me';

QUERYPLAN

--------------------------------------------------------------------------------------------------------------------------

Seq Scan on tbl_index (cost=0.00..140899.00 rows=10000000 width=23) (actual time=0.051..6758.236 rows=10000000 loops=1)

Filter: ((c)::text = 'bit me'::text)

Rows Removedby Filter: 1Planning time:0.128ms

Execution time:7237.900ms

(5rows)

Time:7238.685ms

test=# explain analyze select * from tbl_index where c = 'haha';

QUERYPLAN

----------------------------------------------------------------------------------------------------------------------------

Index Scan using idx_tbl_index_c on tbl_index (cost=0.43..4.45 rows=1 width=23) (actual time=0.063..0.065 rows=1 loops=1)Index Cond: ((c)::text = 'haha'::text)

Planning time:0.219ms

Execution time:2.869ms

(4rows)

Time:4.942 ms

test=# drop indexidx_tbl_index_a;DROP INDEXTime:134.873ms

test=# drop indexidx_tbl_index_c;DROP INDEXTime:173.572 ms

6.多字段btree索引查询条件不包含第一列

test=# explain analyze select * from tbl_index where a = 10000001 and c = 'haha';

QUERYPLAN

--------------------------------------------------------------------------------------------------------------------------------

Index Scan using idx_tbl_index_a_c on tbl_index (cost=0.43..6.20 rows=1 width=23) (actual time=23.254..23.257 rows=1 loops=1)Index Cond: ((a = 10000001) AND ((c)::text = 'haha'::text))

Planning time:36.050ms

Execution time:35.710ms

(4rows)

Time:78.816ms

test=# explain analyze select * from tbl_index where c = 'haha';

QUERYPLAN

-----------------------------------------------------------------------------------------------------------------------------

Gather (cost=1000.00..68982.44 rows=1 width=23) (actual time=7869.579..7890.974 rows=1 loops=1)

Workers Planned:2Workers Launched:2

-> Parallel Seq Scan on tbl_index (cost=0.00..67982.34 rows=0 width=23) (actual time=7468.480..7468.480 rows=0 loops=3)

Filter: ((c)::text = 'haha'::text)

Rows Removedby Filter: 3333333Planning time:0.130ms

Execution time:7891.137ms

(8rows)

Time:7891.937ms

test=# explain analyze select * from tbl_index where a = 10000001;

QUERYPLAN

------------------------------------------------------------------------------------------------------------------------------

Index Scan using idx_tbl_index_a_c on tbl_index (cost=0.43..8.45 rows=1 width=23) (actual time=0.154..0.156 rows=1 loops=1)Index Cond: (a = 10000001)

Planning time:0.257ms

Execution time:0.206ms

(4rows)

Time:1.119 ms

7.多字段索引查询条件使用OR

test=# explain analyze select * from tbl_index where a = 10000001 or c = 'haha';

QUERYPLAN

-----------------------------------------------------------------------------------------------------------------------------

Gather (cost=1000.00..79399.11 rows=1 width=23) (actual time=7321.821..7323.593 rows=1 loops=1)

Workers Planned:2Workers Launched:2

-> Parallel Seq Scan on tbl_index (cost=0.00..78399.01 rows=0 width=23) (actual time=7307.413..7307.413 rows=0 loops=3)

Filter: ((a= 10000001) OR ((c)::text = 'haha'::text))

Rows Removedby Filter: 3333333Planning time:0.163ms

Execution time:7324.821ms

(8rows)

Time:7325.532ms

test=# explain analyze select * from tbl_index where a = 10000001 and c = 'haha';

QUERYPLAN

------------------------------------------------------------------------------------------------------------------------------

Index Scan using idx_tbl_index_a_c on tbl_index (cost=0.43..6.20 rows=1 width=23) (actual time=0.040..0.041 rows=1 loops=1)Index Cond: ((a = 10000001) AND ((c)::text = 'haha'::text))

Planning time:0.165ms

Execution time:0.093ms

(4rows)

Time:32.904 ms

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值