powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / оптимизация доступа к диску
21 сообщений из 21, страница 1 из 1
оптимизация доступа к диску
    #38579167
tdiff
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Имею вот такой план выполнения простого джойна двух таблиц. По индексу type_ts_cashier выбираются записи из таблицы pos_events, после чего эти записи по своему внешнему ключу соединяются с записями из таблицы pos_receipts. План получен "на холодную", сразу после загрузки СУБД и ОС.

Код: sql
1.
2.
3.
4.
5.
6.
7.
'Limit  (cost=0.00..6951.71 rows=500 width=257) (actual time=341.149..2999.962 rows=500 loops=1)'
'  ->  Nested Loop  (cost=0.00..712119.47 rows=51219 width=257) (actual time=341.147..2999.824 rows=500 loops=1)'
'        ->  Index Scan using type_ts_cashier on pos_events  (cost=0.00..296952.83 rows=51219 width=136) (actual time=288.904..766.576 rows=500 loops=1)'
'              Index Cond: ((event_type = 300) AND (event_ts_received >= 1202118750621000::bigint) AND (event_ts_received <= 1393926750621000::bigint) AND (lower(event_cashier_name) = '???°N?N?N?????????N? ??????N???N???N? ?????????»?°?µ?????°'::text))'
'        ->  Index Scan using pos_receipts_pkey on pos_receipts  (cost=0.00..7.84 rows=1 width=121) (actual time=1.970..1.985 rows=1 loops=500)'
'              Index Cond: ((receipt_id)::text = (pos_events.event_receipt_id)::text)'
'Total runtime: 3000.123 ms'


Вот в более читаемом виде:
http://explain.depesz.com/s/Wyl


Вопросы такие:
1. IndexScan'ы 500 записей занимают соответственно 800 и 1000 мс.
С одной стороны, на примере второго IndexScan по pos_receipts_pkey, из плана видно, что это 500 seek по диску, каждый из которых занимает 2мс, что похоже на скорость доступа к диску.
Но, с другой стороны, такое ощущение, что это очень медленно — целую секунду считывать 500 строк, и хочется как-то улучшить результат. Что можно для этого сделать?
receipt_id — это идентификатор записи в таблице pos_receipts, случайный набор символов. На диске записи c receipt_id сейчас лежат в случайном порядке.

2. Что делает NestedLoop внутри себя в течение 1240 мс?
...
Рейтинг: 0 / 0
оптимизация доступа к диску
    #38579639
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
tdiffИмею вот такой план выполнения простого джойна двух таблиц. По индексу type_ts_cashier выбираются записи из таблицы pos_events, после чего эти записи по своему внешнему ключу соединяются с записями из таблицы pos_receipts. План получен "на холодную", сразу после загрузки СУБД и ОС.

Код: sql
1.
2.
3.
4.
5.
6.
7.
'Limit  (cost=0.00..6951.71 rows=500 width=257) (actual time=341.149..2999.962 rows=500 loops=1)'
'  ->  Nested Loop  (cost=0.00..712119.47 rows=51219 width=257) (actual time=341.147..2999.824 rows=500 loops=1)'
'        ->  Index Scan using type_ts_cashier on pos_events  (cost=0.00..296952.83 rows=51219 width=136) (actual time=288.904..766.576 rows=500 loops=1)'
'              Index Cond: ((event_type = 300) AND (event_ts_received >= 1202118750621000::bigint) AND (event_ts_received <= 1393926750621000::bigint) AND (lower(event_cashier_name) = '???°N?N?N?????????N? ??????N???N???N? ?????????»?°?µ?????°'::text))'
'        ->  Index Scan using pos_receipts_pkey on pos_receipts  (cost=0.00..7.84 rows=1 width=121) (actual time=1.970..1.985 rows=1 loops=500)'
'              Index Cond: ((receipt_id)::text = (pos_events.event_receipt_id)::text)'
'Total runtime: 3000.123 ms'


Вот в более читаемом виде:
http://explain.depesz.com/s/Wyl


Вопросы такие:
1. IndexScan'ы 500 записей занимают соответственно 800 и 1000 мс.
С одной стороны, на примере второго IndexScan по pos_receipts_pkey, из плана видно, что это 500 seek по диску, каждый из которых занимает 2мс, что похоже на скорость доступа к диску.
Но, с другой стороны, такое ощущение, что это очень медленно — целую секунду считывать 500 строк, и хочется как-то улучшить результат. Что можно для этого сделать?
receipt_id — это идентификатор записи в таблице pos_receipts, случайный набор символов. На диске записи c receipt_id сейчас лежат в случайном порядке.

2. Что делает NestedLoop внутри себя в течение 1240 мс?

1)или поставить больше памяти чтобы база в основном была в оперативке (а тормоза при холодном старте базы они у всех и всегда)
или вместо механики использовать нормальные серверные ssd (легко может в 100 раз быстрее быть)
Больше особо ничего сделать нельзя... хотя... если индекс у вас сделан как (event_type, lower(name), ts) то поможет cluster первой таблицы по этому индексу...

по 2 лучше всего наверное включить track_io_timing в базе и делать explain (analyze, costs, buffers, timing) там будет виднее что происходит.
...
Рейтинг: 0 / 0
оптимизация доступа к диску
    #38580337
tdiff
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Maxim Boguk1)или поставить больше памяти чтобы база в основном была в оперативке (а тормоза при холодном старте базы они у всех и всегда)
или вместо механики использовать нормальные серверные ssd (легко может в 100 раз быстрее быть)
Больше особо ничего сделать нельзя... хотя... если индекс у вас сделан как (event_type, lower(name), ts) то поможет cluster первой таблицы по этому индексу...

по 2 лучше всего наверное включить track_io_timing в базе и делать explain (analyze, costs, buffers, timing) там будет виднее что происходит.

спасибо, попробую
...
Рейтинг: 0 / 0
оптимизация доступа к диску
    #38581430
Ivan Durak
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
tdiffMaxim Boguk1)или поставить больше памяти чтобы база в основном была в оперативке (а тормоза при холодном старте базы они у всех и всегда)
или вместо механики использовать нормальные серверные ssd (легко может в 100 раз быстрее быть)
Больше особо ничего сделать нельзя... хотя... если индекс у вас сделан как (event_type, lower(name), ts) то поможет cluster первой таблицы по этому индексу...

по 2 лучше всего наверное включить track_io_timing в базе и делать explain (analyze, costs, buffers, timing) там будет виднее что происходит.

спасибо, попробую
хэш джоин попробуй.
...
Рейтинг: 0 / 0
оптимизация доступа к диску
    #38584232
tdiff
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
а как форсиовать использование хэш джойна? set enable_nestloop = false?
...
Рейтинг: 0 / 0
оптимизация доступа к диску
    #38584261
Ivan Durak
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
tdiffа как форсиовать использование хэш джойна? set enable_nestloop = false?
для начала статистику обнови
...
Рейтинг: 0 / 0
оптимизация доступа к диску
    #38584269
tdiff
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ivan Durak,

это само собой default_statistics_target=1000
...
Рейтинг: 0 / 0
оптимизация доступа к диску
    #38584282
Ivan Durak
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
tdiffIvan Durak,

это само собой default_statistics_target=1000
кстати а где запрос? или хотябы условие соединения? там эквисоединение нормальное? типы одинаковые?
...
Рейтинг: 0 / 0
оптимизация доступа к диску
    #38584287
tdiff
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ivan Durak,

Схема такая:

Код: sql
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.
CREATE TABLE pos_receipts
(
  receipt_id character varying(128) NOT NULL,
  -- много других полей
  CONSTRAINT pos_receipts_pkey PRIMARY KEY (receipt_id )
)

CREATE TABLE pos_events
(
  event_ts_received bigint NOT NULL,
  event_type integer NOT NULL,
  event_cashier_name text NOT NULL,
  event_receipt_id character varying(128) NOT NULL,
  -- много других полей
  CONSTRAINT pos_events_pkey PRIMARY KEY (event_ts_received ),
  CONSTRAINT pos_events_event_receipt_id_fkey FOREIGN KEY (event_receipt_id)
      REFERENCES pos_receipts (receipt_id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE CASCADE
)

CREATE INDEX events_receipts_idx
  ON pos_events
  USING btree
  (event_receipt_id COLLATE pg_catalog."default" );

CREATE INDEX type_ts_cashier
  ON pos_events
  USING btree
  (event_type , event_ts_received , lower(event_cashier_name) COLLATE pg_catalog."default" );



индекс type_ts_cashier — сделан специально под наиболее характерные запросы вида:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
SELECT *
FROM pos_events INNER JOIN pos_receipts ON pos_events.event_receipt_id = pos_receipts.receipt_id
WHERE TRUE
AND event_ts_received >= 1202118750621000
AND event_ts_received <= 1393926750621000
AND event_type IN (300)
AND lower(event_cashier_name) = lower('Мартынович Виктория Николаевна')
ORDER BY event_ts_received ASC 
LIMIT 500
...
Рейтинг: 0 / 0
оптимизация доступа к диску
    #38584354
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
покажите пожалуйста

select count(*) from pos_events where event_ts_received >= 1202118750621000 and event_ts_received <= 1393926750621000;
select count(*) from pos_events where event_type = 300;
select count(*) from pos_events where lower(event_cashier_name) = lower('Мартынович Виктория Николаевна');

и, может быть даже, то же кол-во строк по комбинациям этих трех ограничений.

ограничение по event_type сформулировано с использованием IN, там могут оказаться несколько значений?
...
Рейтинг: 0 / 0
оптимизация доступа к диску
    #38584370
tdiff
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
LeXa NalBatпокажите пожалуйста

select count(*) from pos_events where event_ts_received >= 1202118750621000 and event_ts_received <= 1393926750621000;

3748388

select count(*) from pos_events where event_type = 300;

1830397, но event_type = 300 - самое часто встречающееся событие.
например, для event_type=2000 всего найдётся 220869 записей, для event_type=314 - 1720 записей.
На план запроса event_type не влияет.

select count(*) from pos_events where lower(event_cashier_name) = lower('Мартынович Виктория Николаевна');

106439

и, может быть даже, то же кол-во строк по комбинациям этих трех ограничений.

53850

ограничение по event_type сформулировано с использованием IN, там могут оказаться несколько значений?

Да, в случае более общего запроса могут оказаться несколько event_type или event_cashier_name. Но требуется добиться максимальной скорости выполнения запроса именно такого вида, когда задан только один event_type и один event_cashier_name.
...
Рейтинг: 0 / 0
оптимизация доступа к диску
    #38584433
Ivan Durak
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
tdiff53850

Ну вот. Оптимизатор по статистике решил что выберется 500 записей, а выбралось на 2 порядка больше.
500 сиков по индексу возможно и быстрее скана и хэш джоина. А вот 53000 явно медленнее.
Так что хинтуй хэш джоин
...
Рейтинг: 0 / 0
оптимизация доступа к диску
    #38584437
Ivan Durak
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
блин, туплю!! у тебя же там лимит 500!! не поможет хэш,
короче если у тебя рецепты есть для любого event - просто лимит 500 выбери до джоина!
...
Рейтинг: 0 / 0
оптимизация доступа к диску
    #38584442
tdiff
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ivan Durak,

Это да, limit.

Выбирать в отдельную таблицу пробовал, не даёт эффекта. По-моему тут беда в том, что упираюсь в скорость диска. Совет использовать кластер по индексу не подходит, потому что в реальности есть ещё один часто встречающийся запрос, в котором вместо event_cashier_name фильтруется по event_terminal. Абсолютно аналогичный запрос, для которого есть точно такой же индекс (event_type, event_ts, event_terminal). А кластеризовать можно только по одному индексу.
...
Рейтинг: 0 / 0
оптимизация доступа к диску
    #38584481
tdiff,

хазяина, ты порядку словов попутала

вот так попробовай, однако
Код: sql
1.
2.
3.
4.
CREATE INDEX type_ts_cashier
  ON pos_events
  USING btree
  (event_type , lower(event_cashier_name) COLLATE pg_catalog."default" , event_ts_received );
...
Рейтинг: 0 / 0
оптимизация доступа к диску
    #38584525
tdiff
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
йокарный бабайtdiff,

хазяина, ты порядку словов попутала

вот так попробовай, однако
Код: sql
1.
2.
3.
4.
CREATE INDEX type_ts_cashier
  ON pos_events
  USING btree
  (event_type , lower(event_cashier_name) COLLATE pg_catalog."default" , event_ts_received );



Спасибо.
Не повлияло на скорость, что ещё раз подтверждает идею о том, что упирается в ввод\вывод.
Плюс так теряется возможность использовать этот индекс для поиска без фильтрации по event_cashier_name.
...
Рейтинг: 0 / 0
оптимизация доступа к диску
    #38584663
Ivan Durak
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
йокарный бабайtdiff,

хазяина, ты порядку словов попутала

вот так попробовай, однако
Код: sql
1.
2.
3.
4.
CREATE INDEX type_ts_cashier
  ON pos_events
  USING btree
  (event_type , lower(event_cashier_name) COLLATE pg_catalog."default" , event_ts_received );


только не так а event_ts_received на первое место
(event_ts_received, event_type , lower(event_cashier_name) COLLATE pg_catalog."default")
дадим оптимизатору шанс не весь индекс сканить
...
Рейтинг: 0 / 0
оптимизация доступа к диску
    #38584691
[quot tdiff]йокарный бабайtdiff,

<>
Спасибо.
Не повлияло на скорость, что ещё раз подтверждает идею о том, что упирается в ввод\вывод.
Плюс так теряется возможность использовать этот индекс для поиска без фильтрации по event_cashier_name.а план где ?
если я правильно понял результат (и если вы не облажались) то у вас вдоль индекса утеряны записи в pos_receipts -- для INNER JOIN pos_receipts ON pos_events.event_receipt_id = pos_receipts.receipt_id. иначе это был бы максимум луп 500 записей вдоль индекса. А это всяко быстрее 3000, если только индекс у вас не полон дед-роусов (а он - свежий).

и ещё - это по "горячему" или по "холодному" ? т.е. индексы уже в памяти, или ещё нет?



да, а часом в записях у вас не блобы мегабайтные ? тогда откусите их в списке вывода из *, и повторите без них.
...
Рейтинг: 0 / 0
оптимизация доступа к диску
    #38584940
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
[quot йокарный бабай]tdiffпропущено...
а план где ?
если я правильно понял результат (и если вы не облажались) то у вас вдоль индекса утеряны записи в pos_receipts -- для INNER JOIN pos_receipts ON pos_events.event_receipt_id = pos_receipts.receipt_id. иначе это был бы максимум луп 500 записей вдоль индекса. А это всяко быстрее 3000, если только индекс у вас не полон дед-роусов (а он - свежий).

и ещё - это по "горячему" или по "холодному" ? т.е. индексы уже в памяти, или ещё нет?



да, а часом в записях у вас не блобы мегабайтные ? тогда откусите их в списке вывода из *, и повторите без них.

насколько я понимаю вопрос о скорости работы на холодную был в начале...
...
Рейтинг: 0 / 0
оптимизация доступа к диску
    #38584967
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
[quot Maxim Boguk]йокарный бабайпропущено...


насколько я понимаю вопрос о скорости работы на холодную был в начале...500*(2+N[toast]) произвольных доступов -- только на чтение записей. По ~60/(10 000) sec/доступ - те самые 3000[+-] и набегают. Временем поднятия страницы-другой индекса можно и пренебречь.


Т.е. или в память побольше поднимать заранее, для чего её иметь (или SSD ?)
, или думать на предмет кластеризованных (по разному) "мат-вью"[ но это жуткий чемодан без ручки, работающий к тому же только если не часто апдейтится набор, но утяжеляющий базу в разы]


поэтому проще смириться
...
Рейтинг: 0 / 0
оптимизация доступа к диску
    #38585907
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
tdiffНе повлияло на скорость...покажите explain (analyze, buffers) select ... при наличии индекса по (event_type , lower(event_cashier_name), event_ts_received)

tdiffПлюс так теряется возможность использовать этот индекс для поиска без фильтрации по event_cashier_name.да, для поиска без ограничения по event_cashier_name нужно наличие еще одного, другого индекса
...
Рейтинг: 0 / 0
21 сообщений из 21, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / оптимизация доступа к диску
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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