База и таблица ~~~~~~~~~~~~~~ => create database db15; CREATE DATABASE => \c db15 You are now connected to database "db15" as user "postgres". => create table t(a integer, b integer, s varchar(1000)); CREATE TABLE => insert into t(a,b,s) select (random()*99)::integer, (random()*999999)::integer, repeat('x',1000) from generate_series(1,1000000); INSERT 0 1000000 => create index on t(a); CREATE INDEX => vacuum analyze t; VACUUM => set enable_bitmapscan=off; SET Распределение данных: => select count(distinct a), count(distinct b) from t; count | count -------+-------- 100 | 631960 (1 row) Выборка 1% ~~~~~~~~~~ => explain analyze select * from t where a = 1; QUERY PLAN ---------------------------------------------------------------------------------------------------------------------------- Index Scan using t_a_idx on t (cost=0.42..38649.97 rows=9933 width=1012) (actual time=1.870..1544.072 rows=10201 loops=1) Index Cond: (a = 1) Planning time: 1.052 ms Execution time: 1548.652 ms (4 rows) Запретим index scan. => set enable_indexscan=off; SET => explain analyze select * from t where a = 1; QUERY PLAN ------------------------------------------------------------------------------------------------------------- Seq Scan on t (cost=0.00..155358.01 rows=9933 width=1012) (actual time=2.113..3861.927 rows=10201 loops=1) Filter: (a = 1) Rows Removed by Filter: 989799 Planning time: 0.059 ms Execution time: 3873.038 ms (5 rows) Для небольшой выборки доступ по индексу эффективнее. => set enable_indexscan=on; SET Выборка 50% ~~~~~~~~~~~ => explain analyze select * from t where a < 50; QUERY PLAN ---------------------------------------------------------------------------------------------------------------- Seq Scan on t (cost=0.00..155358.01 rows=500434 width=1012) (actual time=0.660..3811.553 rows=500448 loops=1) Filter: (a < 50) Rows Removed by Filter: 499552 Planning time: 0.073 ms Execution time: 3953.923 ms (5 rows) Запретим seq scan. => set enable_seqscan=off; SET => explain analyze select * from t where a < 50; QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------- Index Scan using t_a_idx on t (cost=0.42..584423.95 rows=500434 width=1012) (actual time=0.597..81487.505 rows=500448 loops=1) Index Cond: (a < 50) Planning time: 0.075 ms Execution time: 81714.797 ms (4 rows) Для большой выборки полное сканирование может оказаться более выгодным. => set enable_seqscan=on; SET Порядок сортировки при создании индекса ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Порядок важен для многоколоночных индексов. Построим индекс по столбцам a и b: => create index on t(a, b); CREATE INDEX Индекс может использоваться для такого запроса: => explain select * from t where a < 1 order by a, b; QUERY PLAN ----------------------------------------------------------------------------- Index Scan using t_a_b_idx on t (cost=0.42..20704.30 rows=5233 width=1012) Index Cond: (a < 1) (2 rows) И для такого: => explain select * from t where a < 1 order by a desc, b desc; QUERY PLAN -------------------------------------------------------------------------------------- Index Scan Backward using t_a_b_idx on t (cost=0.42..20704.30 rows=5233 width=1012) Index Cond: (a < 1) (2 rows) Но не для такого (сортировка в разных направлениях): => explain select * from t where a < 1 order by a, b desc; QUERY PLAN --------------------------------------------------------------------------------- Sort (cost=23329.65..23342.73 rows=5233 width=1012) Sort Key: a, b DESC -> Index Scan using t_a_idx on t (cost=0.42..20689.42 rows=5233 width=1012) Index Cond: (a < 1) (4 rows) Здесь приходится отдельно выполнять сортировку результатов. В этом случае поможет другой индекс: => create index t_a_b_desc on t(a, b desc); CREATE INDEX => explain select * from t where a < 1 order by a, b desc; QUERY PLAN ------------------------------------------------------------------------------ Index Scan using t_a_b_desc on t (cost=0.42..20704.30 rows=5233 width=1012) Index Cond: (a < 1) (2 rows) А также для запроса с обратным порядком сортировки: => explain select * from t where a < 1 order by a desc, b; QUERY PLAN --------------------------------------------------------------------------------------- Index Scan Backward using t_a_b_desc on t (cost=0.42..20704.30 rows=5233 width=1012) Index Cond: (a < 1) (2 rows) => \q