powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Использование индекса при GROUP BY
17 сообщений из 17, страница 1 из 1
Использование индекса при GROUP BY
    #34307184
Andrey Daeron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
По мотивам , с удивлением обнаружил, что на 1.7млн. записей (ширина записи width=216) следующий запрос просто неприлично тормозит:
Код: plaintext
1.
2.
3.
4.
5.
SELECT alias_id, max(id) FROM ma_data GROUP BY alias_id

HashAggregate  (cost= 85263 . 28 .. 85263 . 82  rows= 43  width= 8 ) (actual time= 22714 . 523 .. 22714 . 819  rows= 57  loops= 1 )
  ->  Seq Scan on ma_data  (cost= 0 . 00 .. 76374 . 52  rows= 1777752  width= 8 ) (actual time= 23 . 884 .. 11449 . 870  rows= 1777752  loops= 1 )
Total runtime:  22715 . 237  ms
Ясно, что индекс не используется. Попытки его включить - ситуацию в общем ухудшили.
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
EXPLAIN ANALYZE SELECT alias_id, max(id) FROM ma_data GROUP BY alias_id;
                                                                     QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------
 GroupAggregate  (cost= 0 . 00 .. 3057664 . 86  rows= 43  width= 8 ) (actual time= 41 . 801 .. 24659 . 548  rows= 57  loops= 1 )
   ->  Index Scan using reference_9_fk on ma_data  (cost= 0 . 00 .. 3048775 . 57  rows= 1777752  width= 8 ) (actual time= 41 . 735 .. 14434 . 330  rows= 1777752  loops= 1 )
 Total runtime:  24668 . 344  ms
( 3  rows)


Если я правильно понял - то это еще одно место граблей с пневмоприводом Постгресовских славных индексов?
Для сравнения Оракл 10GR2 дает (правда на более узкой таблице) значения порядка 1 сек.
Код: plaintext
1.
2.
3.
4.
5.
SHOW shared_buffers;
 shared_buffers
----------------
 320MB
( 1  row)
...
Рейтинг: 0 / 0
Использование индекса при GROUP BY
    #34307198
Andrey Daeron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Мда. Сам шучу сам смеюсь.
Сделал небольшую проверку:
Код: plaintext
1.
2.
3.
4.
5.
SELECT alias_id, id INTO tmpb_3 FROM ma_data;

SELECT alias_id, max(id) FROM tmpb_3 GROUP BY alias_id;

 1 . 7 - 2 . 5  сек.
Т.е. таки ширина таблицы.
...
Рейтинг: 0 / 0
Использование индекса при GROUP BY
    #34307400
Jelis
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Andrey DaeronМда. Сам шучу сам смеюсь.
Сделал небольшую проверку:
Код: plaintext
1.
2.
3.
4.
5.
SELECT alias_id, id INTO tmpb_3 FROM ma_data;

SELECT alias_id, max(id) FROM tmpb_3 GROUP BY alias_id;

 1 . 7 - 2 . 5  сек.
Т.е. таки ширина таблицы.

А план при этом такой же?
...
Рейтинг: 0 / 0
Использование индекса при GROUP BY
    #34307441
Andrey Daeron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
План:
Код: plaintext
1.
2.
3.
4.
5.
SELECT alias_id, max(id) FROM tmpb_3 GROUP BY alias_id

HashAggregate  (cost= 35382 . 90 .. 35383 . 20  rows= 24  width= 8 ) (actual time= 20505 . 412 .. 20505 . 732  rows= 57  loops= 1 )
  ->  Seq Scan on tmpb_3  (cost= 0 . 00 .. 26493 . 60  rows= 1777860  width= 8 ) (actual time= 0 . 025 .. 9612 . 207  rows= 1777752  loops= 1 )
Total runtime:  20506 . 127  ms
При этом реальное выполнение запроса (без получения плана) - 1.5 сек.
Почему так - ХЗ.
Код: plaintext
1.
2.
3.
4.
5.
6.
SELECT version();
                                                version
-------------------------------------------------------------------------------------------------------
 PostgreSQL  8 . 2 . 1  on i686-redhat-linux-gnu, compiled by GCC gcc (GCC)  4 . 0 . 2   20051125  (Red Hat  4 . 0 . 2 - 8 )
( 1  row)

...
Рейтинг: 0 / 0
Использование индекса при GROUP BY
    #34307458
СергейК
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Andrey DaeronМда. Сам шучу сам смеюсь.

Т.е. таки ширина таблицы.

Ia by vse-taki tak pospeshno ne sudil. (hotia mojet byt' eto i tak).

Nado proveriat' v polnostiu ne-cachirovannom sluchae, i smotret' chto iavliaetsia limitiruiushim factorom, CPU ili I/O. ( grubo govoria zanimaet li 100% cpu postmaster vo vremia zaprosa...)
A tak eto nemnojko pohoje na gadanie na kofeinoi gusche.... IMHO
...
Рейтинг: 0 / 0
Использование индекса при GROUP BY
    #34307526
iiiiiiii
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Код: plaintext
1.
2.
3.
SELECT alias.id
,(SELECT  max(id) FROM ma_data WHERE alias_id = a.id)
FROM alias
а вот такой планчик не покажете?
при индексе (alias_id,id) на ma_data
...
Рейтинг: 0 / 0
Использование индекса при GROUP BY
    #34307548
Andrey Daeron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
СергейК Andrey DaeronМда. Сам шучу сам смеюсь.

Т.е. таки ширина таблицы.

Ia by vse-taki tak pospeshno ne sudil. (hotia mojet byt' eto i tak).

Согласен. Меня просто немного другой вопрос беспокоил.
Доковырлся еще не много:
1. Ставим серверу 500МБ шаред буферов (чтоб таки мог скешить).
2. Первое выполнение:
14 сек.
iostat - 25-30 метров чтение (я так понимаю размер блока 512 байт)
top - 38%.
3. Второе выполнение
3.05 сек
iostat - в передлах 0
top - 100%.

Вывод:
1. Индексы НЕ используются (судя по всему - опять же идеология версионности и "приблизительно-рекомендательный" храктер реализации) - используется seq_scan
2. Основная проблема - закешировать данные в памяти, а там уже все быстро и просто.
т.е. все упирается в тормозной винт. Закешированные данные - прекрастно себе живут, и ничего лишнего не просят. Я считаю что 1.7 млн записей просмотреть и саггрегировать за 3 секунды - вполне простительно.
...
Рейтинг: 0 / 0
Использование индекса при GROUP BY
    #34307559
СергейК
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Andrey Daeron
Согласен. Меня просто немного другой вопрос беспокоил.
Доковырлся еще не много:
1. Ставим серверу 500МБ шаред буферов (чтоб таки мог скешить).
2. Первое выполнение:
14 сек.
iostat - 25-30 метров чтение (я так понимаю размер блока 512 байт)
top - 38%.
3. Второе выполнение
3.05 сек
iostat - в передлах 0
top - 100%.


Nu v takoi formulirovke, u menia nikakih pretenzii k Postgresu toje net. Vse ochen' daje razumno...

Nu a naschet versionnosti i neispolzovania index'ov ia pojalui s vami ne soglashus'. Predstavim sebe, chto Postgres daje by hranil vidimost' tuplov v index'ah, to v zaprose
SELECT alias_id, max(id) FROM tmpb_3 GROUP BY alias_id
emu vse ravno by prishlos' lezt' v osnovnuiu tablitsu chtoby podniat' znachenie kolonki id... T.e. realno emu vse ravno nujno podymat' KAJDYY tuple iz tablitsy... Poetomu ia voobshe ne viju kak index tut chego-to mojet printsipialno uluchshit'...
...
Рейтинг: 0 / 0
Использование индекса при GROUP BY
    #34307644
Andrey Daeron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Чем-то зацепил запрос :(

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
SELECT alias_id, max(id) FROM ma_data GROUP BY alias_id ORDER BY  2  DESC LIMIT  10 
 10  rows fetched ( 13 , 74  sec)

Limit  (cost= 85264 . 98 .. 85265 . 01  rows= 10  width= 8 ) (actual time= 20723 . 796 .. 20723 . 929  rows= 10  loops= 1 )
  ->  Sort  (cost= 85264 . 98 .. 85265 . 09  rows= 43  width= 8 ) (actual time= 20723 . 783 .. 20723 . 823  rows= 10  loops= 1 )
        Sort Key: max(id)
        ->  HashAggregate  (cost= 85263 . 28 .. 85263 . 82  rows= 43  width= 8 ) (actual time= 20723 . 045 .. 20723 . 348  rows= 57  loops= 1 )
              ->  Seq Scan on ma_data  (cost= 0 . 00 .. 76374 . 52  rows= 1777752  width= 8 ) (actual time= 0 . 020 .. 9400 . 080  rows= 1777752  loops= 1 )
Total runtime:  20724 . 130  ms
Индексы есть всякие разные. Все равно не используются :( В теории для каждого alias_id (их всего 57 и эта инфа должна быть и в индексе и в статистике), в другом индексе (по парам) можно было бы найти max(id) и уже его наличие проверить в БД. Впрочем для такого запроса Оракл индексы тоже не использует.

И такой запрос приводит в ступор:
Код: plaintext
1.
2.
3.
4.
5.
SELECT alias_id FROM ma_data GROUP BY alias_id 

HashAggregate  (cost= 80818 . 90 .. 80819 . 33  rows= 43  width= 4 ) (actual time= 20030 . 981 .. 20031 . 281  rows= 57  loops= 1 )
  ->  Seq Scan on ma_data  (cost= 0 . 00 .. 76374 . 52  rows= 1777752  width= 4 ) (actual time= 0 . 025 .. 9190 . 549  rows= 1777752  loops= 1 )
Total runtime:  20031 . 702  ms
Чего здесь индекс не юзать - совсем не понятно :(
...
Рейтинг: 0 / 0
Использование индекса при GROUP BY
    #34307914
СергейК
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Andrey DaeronЧем-то зацепил запрос :(


Индексы есть всякие разные. Все равно не используются :( В теории для каждого alias_id (их всего 57 и эта инфа должна быть и в индексе и в статистике), в другом индексе (по парам) можно было бы найти max(id) и уже его наличие проверить в БД.
Впрочем для такого запроса Оракл индексы тоже не использует.


V teorii da, no ne potrebovalo li by eto slishkom bolshogo chisla seek'ov... Nu v obshem, tak kak Oracle tut index'y ne ispolzuet, to ia schitau tut sporit' ne o chem :-).

Andrey Daeron
И такой запрос приводит в ступор:
Код: plaintext
1.
2.
3.
4.
5.
SELECT alias_id FROM ma_data GROUP BY alias_id 

HashAggregate  (cost= 80818 . 90 .. 80819 . 33  rows= 43  width= 4 ) (actual time= 20030 . 981 .. 20031 . 281  rows= 57  loops= 1 )
  ->  Seq Scan on ma_data  (cost= 0 . 00 .. 76374 . 52  rows= 1777752  width= 4 ) (actual time= 0 . 025 .. 9190 . 549  rows= 1777752  loops= 1 )
Total runtime:  20031 . 702  ms
Чего здесь индекс не юзать - совсем не понятно :(

A tut kak raz chisto effect togo, chto v postgrese vidimost' ne hranitsia v indexe... Postgresu vse ravno nujno podymat' tuply s diska.... poetomu seq. scan okazyvaetsia vygodnee. Tak chto planner tut postupaet absolutno korrectno....
...
Рейтинг: 0 / 0
Использование индекса при GROUP BY
    #34308376
4321
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
СергейК A tut kak raz chisto effect togo, chto v postgrese vidimost' ne hranitsia v indexe... Postgresu vse ravno nujno podymat' tuply s diska.... poetomu seq. scan okazyvaetsia vygodnee. Tak chto planner tut postupaet absolutno korrectno....керню пишете. "абсолютно корректно" - значица - апсалютно минимальные затраты с т.з математятики.
при относительно свежем индексе, для возврата 43 строк нужно просмотреть по несколько записей на одно значение alias_id, и только ~ (57-43) значений alias_id потребует проверку всех записей с этим значением alias_id.



Думаица сама природа индексов в постгресе говорит о том, что оптимизация запросов не была в числе приоритетов раздрабодчикафф И тем более оптимайзер не являица их сильной стороной и теперь. Я вот все думаю, если вместо удаления иметь поле актуальности, включаемое во все индексы (вернее все индексы строить при условии WHERE actual = TRUE, не обеспчит ли это актуальности индекса? Кто готов рассказать, как обстоит дело с условными индексами? остаются ли в них индексы по не удовлетворяющим условию записям? Или остаются - поскольку измначальная версия отвечала условию, а узнать, что версия неактуальна можно только посмотрев запись?
...
Рейтинг: 0 / 0
Использование индекса при GROUP BY
    #34309309
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Для выбора небольшого кол-ва строк из большой таблицы при том, что каждую строку можно быстро выбрать по индексу. ИМХО делать через plpgsql по одному запросу на каждую строку результата. (Как я написал тут .)
...
Рейтинг: 0 / 0
Использование индекса при GROUP BY
    #34309671
Andrey Daeron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
4321Думаица сама природа индексов в постгресе говорит о том, что оптимизация запросов не была в числе приоритетов раздрабодчикафф И тем более оптимайзер не являица их сильной стороной и теперь. Я вот все думаю, если вместо удаления иметь поле актуальности, включаемое во все индексы (вернее все индексы строить при условии WHERE actual = TRUE, не обеспчит ли это актуальности индекса? Кто готов рассказать, как обстоит дело с условными индексами? остаются ли в них индексы по не удовлетворяющим условию записям? Или остаются - поскольку измначальная версия отвечала условию, а узнать, что версия неактуальна можно только посмотрев запись?
Поговрить об условных индексах не готов , но когда-то прочитал в рассылке Постгреса хорошее описание что они понимают под индексом (и откуда берется ре-чек). Индекс - это указание того, что данные удовлетворяющие некоторому условию есть на странице. Ну, например, если есть индекс по alias_id, то в нем будет хранится инфа для каждого уникального значения alias_id на каких страницах есть о них упоминание, и только эти страницы будут при поиске подниматься с винта. Йо. Размер страницы в PG - 8k. Ну в общем как сделан условный индекс - можно или догадаться самим (типа велосипед изобрести ) или глянуть сырцы (для любителей этого дела) или спросить в ихней рассылке. Попробую изобрести велосипед. что такое условный индекс? Это тотже индекс, только в нем кол-во элементов определенно отсечено условием, и если условие выборки совпадает (или приводимо с точки зрения Постгреса) с условием индекса - то он используется. Ну и хранится там информация только про страницы записей попадающих под условие частичного индекса. ИМХО примерно отсюда и берется реализация партиционирования Постгреса.
...
Рейтинг: 0 / 0
Использование индекса при GROUP BY
    #34309822
LeXa NalBat...

я просто предлагал смоделировать ваше предложение посредством запроса _к другой таблице_ (маленькой, которая нверное таки существует) с подзапросом к большой. Причем подзапрос можно переписать в виде
Код: plaintext
1.
2.
SELECT alias.id
,(SELECT  id FROM ma_data WHERE ma_data.alias_id = alias.id ORDER BY id DESC LIMIT  1 ) AS min_id 
FROM alias
почти то же самое оптимизатор, в идеале, мог бы делать (для оригинального запроса автора топика) и сам пользуясь одним лишь индексом (alias_id,id), и единственно - проверяя актуальность в самой таблице, уж раз ему иначе низзя.
...
Рейтинг: 0 / 0
Использование индекса при GROUP BY
    #34309823
LeXa NalBat...

я просто предлагал смоделировать ваше предложение посредством запроса _к другой таблице_ (маленькой, которая нверное таки существует) с подзапросом к большой. Причем подзапрос можно переписать в виде
Код: plaintext
1.
2.
SELECT alias.id
,(SELECT  id FROM ma_data WHERE ma_data.alias_id = alias.id ORDER BY id DESC LIMIT  1 ) AS min_id 
FROM alias
почти то же самое оптимизатор, в идеале, мог бы делать (для оригинального запроса автора топика) и сам пользуясь одним лишь индексом (alias_id,id), и единственно - проверяя актуальность в самой таблице, уж раз ему иначе низзя.
...
Рейтинг: 0 / 0
Использование индекса при GROUP BY
    #34309864
Andrey Daeron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
iiiiiiiiiiiiiiiiiiii
я просто предлагал смоделировать ваше предложение посредством запроса _к другой таблице_ (маленькой, которая нверное таки существует) с подзапросом к большой. Причем подзапрос можно переписать в виде
Код: plaintext
1.
2.
SELECT alias.id
,(SELECT  id FROM ma_data WHERE ma_data.alias_id = alias.id ORDER BY id DESC LIMIT  1 ) AS min_id 
FROM alias
почти то же самое оптимизатор, в идеале, мог бы делать (для оригинального запроса автора топика) и сам пользуясь одним лишь индексом (alias_id,id), и единственно - проверяя актуальность в самой таблице, уж раз ему иначе низзя.
Да, это вполне супер-решение:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
SELECT ma_alias.id, (SELECT  id FROM ma_data WHERE ma_data.alias_id = ma_alias.id ORDER BY id DESC LIMIT  1 ) AS min_id
FROM ma_alias

Seq Scan on ma_alias  (cost= 0 . 00 .. 123 . 79  rows= 50  width= 4 ) (actual time= 0 . 096 .. 3 . 674  rows= 57  loops= 1 )
  SubPlan
    ->  Limit  (cost= 0 . 00 .. 2 . 45  rows= 1  width= 4 ) (actual time= 0 . 042 .. 0 . 047  rows= 1  loops= 57 )
          ->  Index Scan Backward using ma_data_idx3 on ma_data  (cost= 0 . 00 .. 101114 . 01  rows= 41343  width= 4 ) (actual time= 0 . 031 .. 0 . 031  rows= 1  loops= 57 )
                Index Cond: (alias_id = $ 0 )
Total runtime:  4 . 135  ms
Не совсем понял что имеется в виду под (cost=0.00..101114.01 rows=41343 width=4) , но выполняется очень шустро - около 100мс.

Но это не совсем честно.

В общем-то вопрос был скорее теоретический, чем практический.
...
Рейтинг: 0 / 0
Использование индекса при GROUP BY
    #34309933
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
iiiiiiiiiiiiiiiiiiiiя просто предлагал смоделировать ваше предложение посредством запроса _к другой таблице_ (маленькой, которая нверное таки существует) с подзапросом к большой.Да, это пожалуй самое простое. Если таблица alias существует.

iiiiiiiiiiiiiiiiiiiiпочти то же самое оптимизатор, в идеале, мог бы делать (для оригинального запроса автора топика) и сам пользуясь одним лишь индексом (alias_id,id), и единственно - проверяя актуальность в самой таблице, уж раз ему иначе низзя. Тут, мне кажется, можно было бы сделать некий index scan с условием "alias_id::NEXT > alias_id::PREV". (Аналогично тому как делается в функции f_test в примере ниже.)

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
create table test (
  id integer,
  val integer
);

insert into test select generate_series( 1 , 1000000 ),  10 *random();
create index test_val_id on test ( val, id );
vacuum analyze test;

explain
  analyze
select distinct on ( val ) *
  from test order by val, id;

explain
  analyze
select val, min(id)
  from test group by val order by val;

create or replace function f_test()
  returns setof test
  language 'plpgsql'
  as '
    declare
      r test;
    begin
      select * into r from test order by val, id limit 1;
      while r.val is not null loop
        return next r;
        select * into r from test where val>r.val order by val, id limit 1;
      end loop;
      return;
    end;
';

explain
  analyze
select * from f_test();

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
nalbat=> explain
nalbat->   analyze
nalbat-> select distinct on ( val ) *
nalbat->   from test order by val, id;
                                                                QUERY PLAN      
------------------------------------------------------------------------------------------------------------------------------------------
 Unique  (cost= 0 . 00 .. 26020 . 51  rows= 11  width= 8 ) (actual time= 0 . 014 .. 1179 . 004  rows= 11  loops= 1 )
   ->  Index Scan using test_val_id on test  (cost= 0 . 00 .. 23520 . 51  rows= 1000000  width= 8 ) (actual time= 0 . 013 .. 818 . 107  rows= 1000000  loops= 1 )
 Total runtime:  1179 . 051  ms
( 3  rows)

nalbat=>
nalbat=> explain
nalbat->   analyze
nalbat-> select val, min(id)
nalbat->   from test group by val order by val;
                                                         QUERY PLAN             
----------------------------------------------------------------------------------------------------------------------------
 Sort  (cost= 19902 . 33 .. 19902 . 36  rows= 11  width= 8 ) (actual time= 1621 . 792 .. 1621 . 794  rows= 11  loops= 1 )
   Sort Key: val
   ->  HashAggregate  (cost= 19902 . 00 .. 19902 . 14  rows= 11  width= 8 ) (actual time= 1621 . 768 .. 1621 . 773  rows= 11  loops= 1 )
         ->  Seq Scan on test  (cost= 0 . 00 .. 14902 . 00  rows= 1000000  width= 8 ) (actual time= 0 . 005 .. 903 . 352  rows= 1000000  loops= 1 )
 Total runtime:  1621 . 842  ms
( 5  rows)

nalbat=> explain
nalbat->   analyze
nalbat-> select * from f_test();
                                                QUERY PLAN                      
----------------------------------------------------------------------------------------------------------
 Function Scan on f_test  (cost= 0 . 00 .. 12 . 50  rows= 1000  width= 8 ) (actual time= 0 . 315 .. 0 . 317  rows= 11  loops= 1 )
 Total runtime:  0 . 334  ms
( 2  rows)
...
Рейтинг: 0 / 0
17 сообщений из 17, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Использование индекса при GROUP BY
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]