powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Как правильно работать_с/создать индекс?
21 сообщений из 21, страница 1 из 1
Как правильно работать_с/создать индекс?
    #35670280
vGhost
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Не как не пойму правильный механизм работы с индексами. Вобщем суть:
Есть некая таблица с кучей полей, одно из которых vg_id - numeric(10,0) >= 0
Создал btree (hash тоже пробовал) индекс по этому полю. Записей в таблице порядка 5 000 000 (для теста, в реальных условиях планирутся примерно 100 лямов).
Простой запрос select count(*) from tablename where vg_id = 123 выполняется порядка 8 сек.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
EXPLAIN ANALYZE SELECT count(*)  FROM tablename where vg_id =  123 ;
                                                                  QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost= 15353 . 69 .. 15353 . 70  rows= 1  width= 0 ) (actual time= 8101 . 331 .. 8101 . 331  rows= 1  loops= 1 )
   ->  Bitmap Heap Scan on tablename  (cost= 94 . 10 .. 15341 . 65  rows= 4813  width= 0 ) (actual time= 36 . 459 .. 8099 . 647  rows= 4951  loops= 1 )
         Recheck Cond: ((vg_id)::numeric =  123 ::numeric)
         ->  Bitmap Index Scan on idx_tbl_vg_id  (cost= 0 . 00 .. 92 . 90  rows= 4813  width= 0 ) (actual time= 29 . 029 .. 29 . 029  rows= 4951  loops= 1 )
               Index Cond: ((vg_id)::numeric =  123 ::numeric)
 Total runtime:  8101 . 400  ms
( 6  rows)
Объясните как этого избежать. Для простого подсчёта количества записей, как я понял, он использует не только индекс, но и заким то фигом сканирует саму таблицу (чего логично предположить делать смысла нет, я же просто хочу знать сколько записей удовлетворяет запросу, а не данные записи выбирать собираюсь). Я вообщее всю жизнь с mysql работал, а тут вот пришлось с postgresql повозиться, вожусь всего неделю, так что прошу не пиннать сильно :)
...
Рейтинг: 0 / 0
Как правильно работать_с/создать индекс?
    #35670448
Oleg Bartunov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
vGhostНе как не пойму правильный механизм работы с индексами. Вобщем суть:
Есть некая таблица с кучей полей, одно из которых vg_id - numeric(10,0) >= 0
Создал btree (hash тоже пробовал) индекс по этому полю. Записей в таблице порядка 5 000 000 (для теста, в реальных условиях планирутся примерно 100 лямов).
Простой запрос select count(*) from tablename where vg_id = 123 выполняется порядка 8 сек.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
EXPLAIN ANALYZE SELECT count(*)  FROM tablename where vg_id =  123 ;
                                                                  QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost= 15353 . 69 .. 15353 . 70  rows= 1  width= 0 ) (actual time= 8101 . 331 .. 8101 . 331  rows= 1  loops= 1 )
   ->  Bitmap Heap Scan on tablename  (cost= 94 . 10 .. 15341 . 65  rows= 4813  width= 0 ) (actual time= 36 . 459 .. 8099 . 647  rows= 4951  loops= 1 )
         Recheck Cond: ((vg_id)::numeric =  123 ::numeric)
         ->  Bitmap Index Scan on idx_tbl_vg_id  (cost= 0 . 00 .. 92 . 90  rows= 4813  width= 0 ) (actual time= 29 . 029 .. 29 . 029  rows= 4951  loops= 1 )
               Index Cond: ((vg_id)::numeric =  123 ::numeric)
 Total runtime:  8101 . 400  ms
( 6  rows)
Объясните как этого избежать. Для простого подсчёта количества записей, как я понял, он использует не только индекс, но и заким то фигом сканирует саму таблицу (чего логично предположить делать смысла нет, я же просто хочу знать сколько записей удовлетворяет запросу, а не данные записи выбирать собираюсь). Я вообщее всю жизнь с mysql работал, а тут вот пришлось с postgresql повозиться, вожусь всего неделю, так что прошу не пиннать сильно :)

Heap (таблица) сканится для получения информации о видимости записи (постгрес - многоверсионная база),
так как в индексе нет этой инфы. В 8.4 будет проще, так как будут реализованы карты видимости, которые
поднять проще чем таблицу.
...
Рейтинг: 0 / 0
Как правильно работать_с/создать индекс?
    #35670606
vGhost
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Т.е. надо правильно понимать что это особенность PostgreSQL такая, что он не может вычислить количество строк используя один лишь индекс и не сканируя при это сами данные (например найдя в btree индексе текущую позицию, получить в метаданных адрес следующей отличающующейся позиции вычесть адрес текущей и поделить на размер записи получив их количество)? И что "ждать чуда" надо в следующей версии (у мну 8.3.3.)?
Или всётаки есть какие то способы разрешения ситуации иными способами. Вообще кто как решает задачу когда нужно получить просто количество записей удовлетворяющих условию, чтоб например построить тот же список страниц например... Или например задача когда у меня в табличке 90 лямов записей, мне нужно получить сумму по некому полю "А" у которых поле vg_id = 123 при всём при том что записей у которых vg_id = 123 менее 0.1% (90к) он это делает аж:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
explain analyze select count(*) from tablename where vg_id =  234 ;
                                                                   QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost= 288658 . 65 .. 288658 . 66  rows= 1  width= 0 ) (actual time= 151326 . 090 .. 151326 . 090  rows= 1  loops= 1 )
   ->  Bitmap Heap Scan on tbl_tablename  (cost= 1715 . 48 .. 288431 . 14  rows= 91000  width= 0 ) (actual time= 2561 . 802 .. 151297 . 234  rows= 91116  loops= 1 )
         Recheck Cond: ((vg_id)::numeric =  234 ::numeric)
         ->  Bitmap Index Scan on idx_tbl_vg_id  (cost= 0 . 00 .. 1692 . 73  rows= 91000  width= 0 ) (actual time= 2551 . 245 .. 2551 . 245  rows= 91116  loops= 1 )
               Index Cond: ((vg_id)::numeric =  234 ::numeric)
 Total runtime:  151326 . 132  ms
( 6  rows)

Или может подскажете, возможно есть некая возможность отсортировать исходные данные? Т.е. например в mysql у меня была возможность сделать нечто такое:
в 3 часа утра я выполнял следующий запрос:
ALTER TABLE tablename ORDER BY vg_id; Это приводило к тому что таблица пересоздавалась на hdd отсортированная по полю vg_id
В результате это приводило к тому что все записи находились в исходниках на хдд группами по vg_id. Т.к. все запросы в условиях всегда содержали vg_id + наличие индекса, резко ускоряло работу, т.к. бд скажем весит 15 гиг, но записи с vg_id скажем 123 это всего навсего 0.1% от всех записей, т.е. 15мб. В результате, используя индекс, бд точнчо знала что записи с vg_id =123 на диске находятся только с N по N+15 гиг адреса в файле данных, и читала только часть этого файла, при чём не прерывную часть из 15 мб на диске в которых были записи с vg_id = 123 не читая остальных 14 гигов данных. Возможно ли как то тут реализовать подобное? Или придётся делать таблицу "NEW" которая будет унаследована от родительской и в которую вставлять новые данные, а потом в 3 утра делать INSERT INTO parent (SELECT * FROM child ORDER BY vg_id); после чего TRUNCATE TABLE child;
??
Вообще какие есть методы работы с большими объёмами данных?
...
Рейтинг: 0 / 0
Как правильно работать_с/создать индекс?
    #35670623
KRED
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
vGhost,

посмотрите в сторону "cluster table...."

http://www.postgresql.org/docs/8.3/static/sql-cluster.html


Удачи.
...
Рейтинг: 0 / 0
Как правильно работать_с/создать индекс?
    #35670629
eddie
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
2 vGhost :
медленный count - это особенность postgresql, с ней можно только смириться.

если запросы на count одни и те же - можно завести таблицу с заранее подсчитанными значениями и модифицировать её триггерами при добавлении/удалении записей.

2 Oleg Bartunov :
гхм... а н приведёт ли это к обратному эффекту - на таблицах, где практически нет "лишних" версий (то есть невелика доля запросов на delete/update относительно запросов на insert) добавление карты видимости заставит postgres делать лишний seek на реальном select? (индекс - карта - данные). или карта маленькая и подразумевается, что она всегда лежит в кэше?
...
Рейтинг: 0 / 0
Как правильно работать_с/создать индекс?
    #35670683
gray hemp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
eddie2 vGhost :
медленный count - это особенность postgresql, с ней можно только смириться.

если запросы на count одни и те же - можно завести таблицу с заранее подсчитанными значениями и модифицировать её триггерами при добавлении/удалении записей.

2 Oleg Bartunov :
гхм... а н приведёт ли это к обратному эффекту - на таблицах, где практически нет "лишних" версий (то есть невелика доля запросов на delete/update относительно запросов на insert) добавление карты видимости заставит postgres делать лишний seek на реальном select? (индекс - карта - данные). или карта маленькая и подразумевается, что она всегда лежит в кэше?
Позволю себе ответить за Олега - нет, к обратному эффекту, относительно текущей ситуации, не приведёт. Да, новая карта будет очень маленькой и подразумевается, что будет поднятой в память. Всё это подробно, с примерами и по-русски расписано тут .
...
Рейтинг: 0 / 0
Как правильно работать_с/создать индекс?
    #35671020
eddie
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ничего там не написано ;)

Что ещё? Чтобы сделать это Haikki пришлось реализовать так называемые "дополнительные отношения" ("Relation forks"). И это важно, потому что (насколько я понимаю, если я понял не правильно, пожалуйста, поправьте меня) они могут (и наверняка будут) использоваться для хранения "карт видимости" ("visibility maps"), которые сделают vacuum более быстрым (и возможно повлияют на индексные сканирования, но это только моя догадка).
...
Рейтинг: 0 / 0
Как правильно работать_с/создать индекс?
    #35675062
vGhost
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
eddie
медленный count - это особенность postgresql, с ней можно только смириться.

если запросы на count одни и те же - можно завести таблицу с заранее подсчитанными значениями и модифицировать её триггерами при добавлении/удалении записей.

Ыхх :(
Жаль, ну да ладно, это я ещё могу обойти, хотябы тем же триггером и отдельной таблицей, к сожалению это не единственная проблема.
Я там второй раз выше не правильный запрос привёл, не то скопипастил, изначально планировалось:
EXPLAIN ANALYZE SELECT sum(in) FROM tablename where vg_id = 123; Но результат вобщем то получается тот же (173185.578 ms).
К сожалению полей которые будут участвовать в подсчёте несколько и вариантов как самих считаемых полей, так и дополнительных условий к vg_id будет тоже много разных, так что триггер при инсерт и апдейт тут не поможет. :(

Но у меня "родилась" ещё одна интересная идея, не знаю как оно поведёт себя на практике, пока не экспериментировал, попробую на выходных, а то и так уже дыру в винте протёр экспериментами, но суть её заключается в следующем:
В таблице порядка 16 полей (некоторые переменной длины!), но условия выборки всегда будут затрагивать только 4 из них. Остальные будут "выбираться/считаться" и т.д. А ещё как известно первичный ключ в любой бд работает очень быстро. Следовательно разделив таблицу на 2, в одной 4 поля по которым будет происходить выборка + ключевое поле, а во второй ключевое поле для связи с первой и все остальные "большие" поля. Тем самым уменьшу размер читаемых базой файлов по которым происходит логическая выборка, и через left join соединю их в запросе. В результате запрос будет в условии по первой табличке в которой запись будет фиксированной длины, и которая будет сравнительно маленькая, после чего имея только нужные точные уникальные ID по уникальному ключу она при обработке LEFT JOIN вытащит данные из второй таблицы. Что должно в теории работать очень быстро. Особенно если это связать с предложенной KRED'ом кластеризацией. И сегментированием:

где-то-в-инетеСегментирование данных можно организовать с помощью наследования (TABLE INHERITANCE) и CE (CONSTRAINT EXCLUSION). Идея состоит в том, чтобы иметь родительскую таблицу (класс), которая определяет основной набор атрибутов и таблицы, которые наследуют структуру родительской таблицы, но имеющие определенные ограничения на параметр, по которому проводится сегментирование. Механизм наследования в PostgreSQL обеспечивает выполнение запроса по всем таблицам автоматически, при этом наличие CE позволяет просматривать только те таблицы, которые удовлетворяют условию на параметр. Типичная ситуация, когда сегментирование идет по времени, например, для хранение журналов веб-серверов.

---------- :)

KRED
посмотрите в сторону "cluster table...."

http://www.postgresql.org/docs/8.3/static/sql-cluster.html

Удачи.

Спасибо, очень помогло :) Время выполнения основных запросов упало до менее 1 сек.
Вот только есть одно "но", по той ссылке в подзаголовке "Note" написано что эта кластеризация может очень долго выполняться на больших таблицах, а также если делать её в "вакууме" что планёр может не оптимально это делать, и что порой лучше бывает делать её самому путём "INSERT FROM SELECT" с сортировкой по нужному полю. Если есть у кого опыт в данном вопросе очень хотелось бы выслушать опытных людей. А также я пока не нашёл можно ли каким нибудь образом, не применяя полного копирования данных во временные таблицы, сделать кластеризацию не по индексу в текущей таблице, а скажем у меня 2 связанные таблички по ключам, используя индекс во второй по какому то полю отсортировать данные в них обоих.
...
Рейтинг: 0 / 0
Как правильно работать_с/создать индекс?
    #35675162
eddie
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
в общем случае join существенно медленнее, чем выборка из одной таблицы.
...
Рейтинг: 0 / 0
Как правильно работать_с/создать индекс?
    #35675252
gray hemp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
eddieничего там не написано ;)

Что ещё? Чтобы сделать это Haikki пришлось реализовать так называемые "дополнительные отношения" ("Relation forks"). И это важно, потому что (насколько я понимаю, если я понял не правильно, пожалуйста, поправьте меня) они могут (и наверняка будут) использоваться для хранения "карт видимости" ("visibility maps"), которые сделают vacuum более быстрым (и возможно повлияют на индексные сканирования, но это только моя догадка).
-rw------- 1 pgdba pgdba 409600000 2008-10-04 13:05 /home/pgdba/data/base/16385/16408
-rw------- 1 pgdba pgdba 122880 2008-10-04 13:05 /home/pgdba/data/base/16385/16408_1

122880/409600000 для 100000 записей

И что случится, если я сделаю update 50% записей?

# update x set dummy_text = repeat('_test_', 500) where id <= 50000;
UPDATE 50000

# \! ls -l $PGDATA/base/16385/16408*
-rw------- 1 pgdba pgdba 614400000 2008-10-04 13:09 /home/pgdba/data/base/16385/16408
-rw------- 1 pgdba pgdba 172032 2008-10-04 13:08 /home/pgdba/data/base/16385/16408_1

Это говорит, что излишек данных на диске составляет около 0.03%, что является незначительным.

Что не так?
...
Рейтинг: 0 / 0
Как правильно работать_с/создать индекс?
    #35675298
eddie
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
gray hemp,

статья вообще-то про изменения в fsm, кто сказал, что в этих 0.03% сидят "visibility maps"?
...
Рейтинг: 0 / 0
Как правильно работать_с/создать индекс?
    #35675335
gray hemp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
eddie,
Возможно вы правы, что в статье нет чёткого указания на то, что VM будет храниться в "дополнительных отношениях", но, почему-то у меня не возникает сомнений по этому поводу. Думаю, если поискать в списках рассылки, то можно будет найти подтверждение.
...
Рейтинг: 0 / 0
Как правильно работать_с/создать индекс?
    #35675338
gray hemp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
eddie,
Кстати, вот и подтверждение http://archives.postgresql.org/pgsql-hackers/2008-10/msg01306.php
...
Рейтинг: 0 / 0
Как правильно работать_с/создать индекс?
    #35676086
KRED
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
gray hempСпасибо, очень помогло :) Время выполнения основных запросов упало до менее 1 сек.
Вот только есть одно "но", по той ссылке в подзаголовке "Note" написано что эта кластеризация может очень долго выполняться на больших таблицах, а также если делать её в "вакууме" что планёр может не оптимально это делать, и что порой лучше бывает делать её самому путём "INSERT FROM SELECT" с сортировкой по нужному полю. Если есть у кого опыт в данном вопросе очень хотелось бы выслушать опытных людей. А также я пока не нашёл можно ли каким нибудь образом, не применяя полного копирования данных во временные таблицы, сделать кластеризацию не по индексу в текущей таблице, а скажем у меня 2 связанные таблички по ключам, используя индекс во второй по какому то полю отсортировать данные в них обоих.

Как вариант предложу прикрутит сюда ещо и партиционирование ... новые данные заливаеш в новые партиции после чего их "сластеризируеш" , а старые лежат на соседних партициях и не меняются. Это конечно если ты данные в основном добавляеш и не изменяеш их рандомно ... , но как мне кажется ты же какето "логи" анализируеш.

Хотя если ты ещо и один из основных поисковых критериев разделиш по партициям то скорость ещо немного увеличится.

http://www.postgresql.org/docs/8.3/static/ddl-partitioning.html
...
Рейтинг: 0 / 0
Как правильно работать_с/создать индекс?
    #35677468
vGhost
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
KRED
Как вариант предложу прикрутит сюда ещо и партиционирование ... новые данные заливаеш в новые партиции после чего их "сластеризируеш" , а старые лежат на соседних партициях и не меняются. Это конечно если ты данные в основном добавляеш и не изменяеш их рандомно ... , но как мне кажется ты же какето "логи" анализируеш.

Хотя если ты ещо и один из основных поисковых критериев разделиш по партициям то скорость ещо немного увеличится.

http://www.postgresql.org/docs/8.3/static/ddl-partitioning.html

Да, вы правы это в каком то смысле "логи", изменяться они правда тоже будут, но будет это один раз в жизни, в течении первых суток, за которым уже можно сделать кластеризацию и партиционирование. На данный момент пока остановился на том что буду сначала складывать всё новое в таблицу "new" (которая тоже будет частью партиции) откуда уже после обработки данные переносить по партициям, которые уже не будут меняться, отсортированные внутри партиции по vg_id, и разделённые по датам (к сожалению по основному критерию vg_id разделить не получится, это хоть и int идентификатор, но "предсказать" его нельзя даже по диапазону, т.к. одних может быть очень много). Пока хочу поэкспериментировать, найти т.н. "золотую середину" в размерах этих частей по дате. Правда про партиционирование я уже читал, только там где я об этом читал, это называли сегментированием, о чём выше я уже писал, но сути это не меняет, всё равно спасибо за совет :)
...
Рейтинг: 0 / 0
Как правильно работать_с/создать индекс?
    #35677476
vGhost
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
*** но "предсказать" его нельзя даже по диапазону, т.к. одних может быть очень много, а других очень мало).***

P.S. чёта я не найду кнопки редактирования :(
...
Рейтинг: 0 / 0
Как правильно работать_с/создать индекс?
    #35677569
KRED
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
vGhost*** но "предсказать" его нельзя даже по диапазону, т.к. одних может быть очень много, а других очень мало).***

P.S. чёта я не найду кнопки редактирования :(

значит делайте по дате , но учтите что большое количество партиций неочень хорошо действует на здоровье постгресу. пару десятков да ... а пару сотен скорее уже перебор.

Я бы сделал табличку текущих данных , которые могут меняться , и табличку партиционированую по месяцам(на крайний случай по неделям) для "архивных данных". После переброски данных в архивную кластеризировал ту партицию что поменял ... или рассмотрел возможность "insert into ... select * from table ORDER BY" Хотя кластеризировать и перестроить индексы для нее самое то ...
...
Рейтинг: 0 / 0
Как правильно работать_с/создать индекс?
    #35677869
eddie
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
KREDзначит делайте по дате , но учтите что большое количество партиций неочень хорошо действует на здоровье постгресу. пару десятков да ... а пару сотен скорее уже перебор. почему?
...
Рейтинг: 0 / 0
Как правильно работать_с/создать индекс?
    #35678715
Andrey Daeron
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
eddieKREDзначит делайте по дате , но учтите что большое количество партиций неочень хорошо действует на здоровье постгресу. пару десятков да ... а пару сотен скорее уже перебор. почему?
Тратится время на поиск нужной партиции. Т.е. проверяются все условия формирований партиций, что подтормаживает.
...
Рейтинг: 0 / 0
Как правильно работать_с/создать индекс?
    #35678966
KRED
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
eddieKREDзначит делайте по дате , но учтите что большое количество партиций неочень хорошо действует на здоровье постгресу. пару десятков да ... а пару сотен скорее уже перебор. почему?


Поищите в форуме .... , а в двух словах "Andrey Daeron" уже ответил.
...
Рейтинг: 0 / 0
Как правильно работать_с/создать индекс?
    #35681094
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
KREDПоищите в форуметут: http://sql.ru/forum/actualthread.aspx?tid=558070
...
Рейтинг: 0 / 0
21 сообщений из 21, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Как правильно работать_с/создать индекс?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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