当前位置:   article > 正文

PostgreSql 索引失效_pg联合索引使用范围查询失效

pg联合索引使用范围查询失效

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

1、任何计算、函数、类型转换
2、!=
3、NOT,相当于使用函数
4、模糊查询通配符在开头
5、索引字段在表中占比较高
6、多字段btree索引查询条件不包含第一列
7、多字段索引查询条件使用OR(有时也会走索引扫描,但查询效率不高)

 

  1. test=# \timing
  2. Timing is on.
  3. test=# create table tbl_index(a bigint,b timestamp without time zone ,c varchar(12));
  4. CREATE TABLE
  5. Time: 147.366 ms
  6. test=# insert into tbl_index select generate_series(1,10000000),clock_timestamp()::timestamp without time zone,'bit me';
  7. INSERT 0 10000000
  8. Time: 30982.723 ms

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

 

  1. crtest=# create index idx_tbl_index_a on tbl_index (a);
  2. CREATE INDEX
  3. Time: 19634.874 ms
  4. test=#
  5. test=# explain analyze select * from tbl_index where a = 1;
  6. QUERY PLAN
  7. ------------------------------------------------------------------------------------------------------------------------------
  8. 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)
  9. Index Cond: (a = 1)
  10. Planning time: 22.788 ms
  11. Execution time: 60.011 ms
  12. (4 rows)
  13. Time: 84.865 ms
  14. test=# explain analyze select * from tbl_index where a + 1 = 1;
  15. QUERY PLAN
  16. ---------------------------------------------------------------------------------------------------------------------------------
  17. Gather (cost=1000.00..84399.00 rows=50000 width=23) (actual time=7678.109..7678.109 rows=0 loops=1)
  18. Workers Planned: 2
  19. Workers Launched: 2
  20. -> 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)
  21. Filter: ((a + 1) = 1)
  22. Rows Removed by Filter: 3333333
  23. Planning time: 0.112 ms
  24. Execution time: 7688.615 ms
  25. (8 rows)
  26. Time: 7780.024 ms
  27. test=# explain analyze select * from tbl_index where power(a,2) = 1;
  28. QUERY PLAN
  29. ---------------------------------------------------------------------------------------------------------------------------------
  30. Gather (cost=1000.00..94815.67 rows=50000 width=23) (actual time=47.516..6902.399 rows=1 loops=1)
  31. Workers Planned: 2
  32. Workers Launched: 2
  33. -> 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)
  34. Filter: (power((a)::double precision, '2'::double precision) = '1'::double precision)
  35. Rows Removed by Filter: 3333333
  36. Planning time: 13.564 ms
  37. Execution time: 6904.232 ms
  38. (8 rows)
  39. Time: 7051.482 ms
  40. test=#
  41. test=# explain analyze select * from tbl_index where a::varchar = '1';
  42. QUERY PLAN
  43. ---------------------------------------------------------------------------------------------------------------------------------
  44. Gather (cost=1000.00..94815.67 rows=50000 width=23) (actual time=1.239..6689.272 rows=1 loops=1)
  45. Workers Planned: 2
  46. Workers Launched: 2
  47. -> 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)
  48. Filter: (((a)::character varying)::text = '1'::text)
  49. Rows Removed by Filter: 3333333
  50. Planning time: 1.029 ms
  51. Execution time: 6692.329 ms
  52. (8 rows)
  53. 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、!=

 

  1. test=# explain analyze select * from tbl_index where a != 1;
  2. QUERY PLAN
  3. -------------------------------------------------------------------------------------------------------------------------
  4. Seq Scan on tbl_index (cost=0.00..140899.00 rows=9999999 width=23) (actual time=0.049..11004.864 rows=9999999 loops=1)
  5. Filter: (a <> 1)
  6. Rows Removed by Filter: 1
  7. Planning time: 0.206 ms
  8. Execution time: 11585.859 ms
  9. (5 rows)
  10. Time: 11587.146 ms

3、NOT,相当于使用函数

 

  1. test=# explain analyze select * from tbl_index where a is null;
  2. QUERY PLAN
  3. ------------------------------------------------------------------------------------------------------------------------------
  4. 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)
  5. Index Cond: (a IS NULL)
  6. Planning time: 33.783 ms
  7. Execution time: 41.838 ms
  8. (4 rows)
  9. Time: 102.544 ms
  10. test=# explain analyze select * from tbl_index where a is not null;
  11. QUERY PLAN
  12. --------------------------------------------------------------------------------------------------------------------------
  13. Seq Scan on tbl_index (cost=0.00..115899.00 rows=10000000 width=23) (actual time=3.062..6309.908 rows=10000000 loops=1)
  14. Filter: (a IS NOT NULL)
  15. Planning time: 0.099 ms
  16. Execution time: 6877.566 ms
  17. (4 rows)
  18. 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性能高,看来情况不同,性能也是不一定的。

 

  1. test=# explain analyze select * from tbl_index where a not in (select a from tbl_test );
  2. QUERY PLAN
  3. -------------------------------------------------------------------------------------------------------------------------
  4. Seq Scan on tbl_index (cost=14.50..140913.50 rows=5000000 width=23) (actual time=1.393..3717.312 rows=9999000 loops=1)
  5. Filter: (NOT (hashed SubPlan 1))
  6. Rows Removed by Filter: 1000
  7. SubPlan 1
  8. -> Seq Scan on tbl_test (cost=0.00..12.00 rows=1000 width=8) (actual time=0.038..0.236 rows=1000 loops=1)
  9. Planning time: 0.134 ms
  10. Execution time: 4147.857 ms
  11. (7 rows)
  12. Time: 4148.615 ms
  13. test=# explain analyze select * from tbl_index where not exists (select null from tbl_test where tbl_test.a = tbl_index.a);
  14. QUERY PLAN
  15. -------------------------------------------------------------------------------------------------------------------------------------
  16. --------------------
  17. Merge Anti Join (cost=62.45..218187.26 rows=9999000 width=23) (actual time=1.698..16909.581 rows=9999000 loops=1)
  18. Merge Cond: (tbl_index.a = tbl_test.a)
  19. -> Index Scan using idx_tbl_index_a on tbl_index (cost=0.43..193110.43 rows=10000000 width=23) (actual time=0.035..14781.400 row
  20. s=10000000 loops=1)
  21. -> Sort (cost=61.83..64.33 rows=1000 width=8) (actual time=0.390..0.659 rows=1000 loops=1)
  22. Sort Key: tbl_test.a
  23. Sort Method: quicksort Memory: 71kB
  24. -> Seq Scan on tbl_test (cost=0.00..12.00 rows=1000 width=8) (actual time=0.038..0.194 rows=1000 loops=1)
  25. Planning time: 0.339 ms
  26. Execution time: 17530.472 ms
  27. (9 rows)
  28. Time: 17594.258 ms

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

 

  1. test=# explain analyze select * from tbl_index where c like 'bit%';
  2. QUERY PLAN
  3. --------------------------------------------------------------------------------------------------------------------------
  4. Seq Scan on tbl_index (cost=0.00..140899.00 rows=10000000 width=23) (actual time=0.099..1685.317 rows=10000000 loops=1)
  5. Filter: ((c)::text ~~ 'bit%'::text)
  6. Planning time: 55.373 ms
  7. Execution time: 2104.863 ms
  8. (4 rows)
  9. Time: 2164.464 ms
  10. test=# explain analyze select * from tbl_index where c like '%me';
  11. QUERY PLAN
  12. ---------------------------------------------------------------------------------------------------------------------------
  13. Seq Scan on tbl_index (cost=0.00..140899.00 rows=10000000 width=23) (actual time=20.172..5507.741 rows=10000000 loops=1)
  14. Filter: ((c)::text ~~ '%me'::text)
  15. Planning time: 65.603 ms
  16. Execution time: 6007.367 ms
  17. (4 rows)

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

 

  1. test=# insert into tbl_index values (10000001,'2015-05-23 00:00:00','haha');
  2. INSERT 0 1
  3. Time: 88.226 ms
  4. test=# explain analyze select * from tbl_index where c = 'bit me';
  5. QUERY PLAN
  6. --------------------------------------------------------------------------------------------------------------------------
  7. Seq Scan on tbl_index (cost=0.00..140899.00 rows=10000000 width=23) (actual time=0.051..6758.236 rows=10000000 loops=1)
  8. Filter: ((c)::text = 'bit me'::text)
  9. Rows Removed by Filter: 1
  10. Planning time: 0.128 ms
  11. Execution time: 7237.900 ms
  12. (5 rows)
  13. Time: 7238.685 ms
  14. test=# explain analyze select * from tbl_index where c = 'haha';
  15. QUERY PLAN
  16. ----------------------------------------------------------------------------------------------------------------------------
  17. 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)
  18. Index Cond: ((c)::text = 'haha'::text)
  19. Planning time: 0.219 ms
  20. Execution time: 2.869 ms
  21. (4 rows)
  22. Time: 4.942 ms
  23. test=# drop index idx_tbl_index_a;
  24. DROP INDEX
  25. Time: 134.873 ms
  26. test=# drop index idx_tbl_index_c;
  27. DROP INDEX
  28. Time: 173.572 ms

 

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

 

  1. test=# explain analyze select * from tbl_index where a = 10000001 and c = 'haha';
  2. QUERY PLAN
  3. --------------------------------------------------------------------------------------------------------------------------------
  4. 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)
  5. Index Cond: ((a = 10000001) AND ((c)::text = 'haha'::text))
  6. Planning time: 36.050 ms
  7. Execution time: 35.710 ms
  8. (4 rows)
  9. Time: 78.816 ms
  10. test=# explain analyze select * from tbl_index where c = 'haha';
  11. QUERY PLAN
  12. -----------------------------------------------------------------------------------------------------------------------------
  13. Gather (cost=1000.00..68982.44 rows=1 width=23) (actual time=7869.579..7890.974 rows=1 loops=1)
  14. Workers Planned: 2
  15. Workers Launched: 2
  16. -> 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)
  17. Filter: ((c)::text = 'haha'::text)
  18. Rows Removed by Filter: 3333333
  19. Planning time: 0.130 ms
  20. Execution time: 7891.137 ms
  21. (8 rows)
  22. Time: 7891.937 ms
  23. test=# explain analyze select * from tbl_index where a = 10000001;
  24. QUERY PLAN
  25. ------------------------------------------------------------------------------------------------------------------------------
  26. 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)
  27. Index Cond: (a = 10000001)
  28. Planning time: 0.257 ms
  29. Execution time: 0.206 ms
  30. (4 rows)
  31. Time: 1.119 ms

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

 

  1. test=# explain analyze select * from tbl_index where a = 10000001 or c = 'haha';
  2. QUERY PLAN
  3. -----------------------------------------------------------------------------------------------------------------------------
  4. Gather (cost=1000.00..79399.11 rows=1 width=23) (actual time=7321.821..7323.593 rows=1 loops=1)
  5. Workers Planned: 2
  6. Workers Launched: 2
  7. -> 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)
  8. Filter: ((a = 10000001) OR ((c)::text = 'haha'::text))
  9. Rows Removed by Filter: 3333333
  10. Planning time: 0.163 ms
  11. Execution time: 7324.821 ms
  12. (8 rows)
  13. Time: 7325.532 ms
  14. test=# explain analyze select * from tbl_index where a = 10000001 and c = 'haha';
  15. QUERY PLAN
  16. ------------------------------------------------------------------------------------------------------------------------------
  17. 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)
  18. Index Cond: ((a = 10000001) AND ((c)::text = 'haha'::text))
  19. Planning time: 0.165 ms
  20. Execution time: 0.093 ms
  21. (4 rows)
  22. Time: 32.904 ms

 

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

闽ICP备14008679号