Ці еквіваленти? Якщо ні, то чому?
Індекс (user_id1, user_id2) та Index (user_id2, user_id1)
Вони не є еквівалентними, і загалом кажучи, індекс (bar, baz) не буде ефективним для запитів форми select * from foo where baz=?
Ервін продемонстрував, що такі індекси дійсно можуть пришвидшити запит, але цей ефект обмежений і не є таким же порядком, як ви, як правило, очікуєте, що індекс покращить пошук - він покладається на те, що часто «повне сканування» індексу часто швидше, ніж "повне сканування" індексованої таблиці завдяки додатковим стовпцям таблиці, які не відображаються в індексі.
Підсумок: індекси можуть допомагати запитам навіть у непровідних стовпцях, але одним із двох вторинних та відносно незначних способів, а не драматичним способом, як правило, ви очікуєте, що індекс допоможе завдяки структурі btree
nb два способи, за якими може допомогти індекс, - це якщо повне сканування індексу значно дешевше, ніж повне сканування таблиці, і будь-яке: 1. Шукання таблиці є дешевими (тому що їх небагато або вони кластеризовані), або 2. індекс охоплює, щоб не було запитів на таблицю взагалі , дивіться коментарі Ервінса тут
тестова площадка:
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