Это эквивалентно? Если нет, то почему?
Индекс (user_id1, user_id2) и Индекс (user_id2, user_id1)
Они не эквивалентны и, вообще говоря, индекс (bar, baz) не будет эффективен для запросов вида select * from foo where baz=?
Эрвин продемонстрировал, что такие индексы действительно могут ускорить запрос, но этот эффект ограничен и не имеет того порядка, в котором вы обычно ожидаете, что индекс улучшает поиск - он основан на том факте, что «полное сканирование» индекса часто быстрее, чем «полное сканирование» индексированной таблицы из-за дополнительных столбцов в таблице, которые не отображаются в индексе.
Резюме: индексы могут помочь в запросах даже для не ведущих столбцов, но одним из двух второстепенных и относительно второстепенных способов, причем не так драматично, как обычно, вы ожидаете, что индекс будет помогать из-за его структуры btree
Обратите внимание на то, что индекс может помочь в двух случаях: если полное сканирование индекса значительно дешевле, чем полное сканирование таблицы, и либо: 1. поиск в таблице дешев (потому что их мало или они кластеризованы), либо 2. индекс покрывает, поэтому нет поиска таблиц вообще , смотрите Erwins комментарии здесь
обкатки:
create table foo(bar integer not null, baz integer not null, qux text not null);
insert into foo(bar, baz, qux)
select random()*100, random()*100, 'some random text '||g from generate_series(1,10000) g;
запрос 1 (без индекса, с 74 буферами ):
explain (buffers, analyze, verbose) select max(qux) from foo where baz=0;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------
Aggregate (cost=181.41..181.42 rows=1 width=32) (actual time=3.301..3.302 rows=1 loops=1)
Output: max(qux)
Buffers: shared hit=74
-> Seq Scan on stack.foo (cost=0.00..181.30 rows=43 width=32) (actual time=0.043..3.228 rows=52 loops=1)
Output: bar, baz, qux
Filter: (foo.baz = 0)
Buffers: shared hit=74
Total runtime: 3.335 ms
запрос 2 (с индексом - оптимизатор игнорирует индекс - снова выбрав 74 буфера ):
create index bar_baz on foo(bar, baz);
explain (buffers, analyze, verbose) select max(qux) from foo where baz=0;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------
Aggregate (cost=199.12..199.13 rows=1 width=32) (actual time=3.277..3.277 rows=1 loops=1)
Output: max(qux)
Buffers: shared hit=74
-> Seq Scan on stack.foo (cost=0.00..199.00 rows=50 width=32) (actual time=0.043..3.210 rows=52 loops=1)
Output: bar, baz, qux
Filter: (foo.baz = 0)
Buffers: shared hit=74
Total runtime: 3.311 ms
запрос 2 (с индексом - и мы обманываем оптимизатор, чтобы использовать его):
explain (buffers, analyze, verbose) select max(qux) from foo where bar>-1000 and baz=0;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=115.56..115.57 rows=1 width=32) (actual time=1.495..1.495 rows=1 loops=1)
Output: max(qux)
Buffers: shared hit=36 read=30
-> Bitmap Heap Scan on stack.foo (cost=73.59..115.52 rows=17 width=32) (actual time=1.370..1.428 rows=52 loops=1)
Output: bar, baz, qux
Recheck Cond: ((foo.bar > (-1000)) AND (foo.baz = 0))
Buffers: shared hit=36 read=30
-> Bitmap Index Scan on bar_baz (cost=0.00..73.58 rows=17 width=0) (actual time=1.356..1.356 rows=52 loops=1)
Index Cond: ((foo.bar > (-1000)) AND (foo.baz = 0))
Buffers: shared read=30
Total runtime: 1.535 ms
Таким образом, доступ через индекс в два раза быстрее в этом случае, задействуя 30 буферов - что с точки зрения индексации «немного быстрее» !, и YMMV в зависимости от относительного размера таблицы и индекса, а также от количества отфильтрованных строк и характеристик кластеризации. данных в таблице
Напротив, запросы к ведущему столбцу используют структуру индекса btree - в этом случае используется 2 буфера :
explain (buffers, analyze, verbose) select max(qux) from foo where bar=0;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=75.70..75.71 rows=1 width=32) (actual time=0.172..0.173 rows=1 loops=1)
Output: max(qux)
Buffers: shared hit=38
-> Bitmap Heap Scan on stack.foo (cost=4.64..75.57 rows=50 width=32) (actual time=0.036..0.097 rows=59 loops=1)
Output: bar, baz, qux
Recheck Cond: (foo.bar = 0)
Buffers: shared hit=38
-> Bitmap Index Scan on bar_baz (cost=0.00..4.63 rows=50 width=0) (actual time=0.024..0.024 rows=59 loops=1)
Index Cond: (foo.bar = 0)
Buffers: shared hit=2
Total runtime: 0.209 ms