Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / оптимизация доступа к диску / 21 сообщений из 21, страница 1 из 1
05.03.2014, 15:56:34
    #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
06.03.2014, 01:27:58
    #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
06.03.2014, 15:39:50
    #38580337
tdiff
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
оптимизация доступа к диску
Maxim Boguk1)или поставить больше памяти чтобы база в основном была в оперативке (а тормоза при холодном старте базы они у всех и всегда)
или вместо механики использовать нормальные серверные ssd (легко может в 100 раз быстрее быть)
Больше особо ничего сделать нельзя... хотя... если индекс у вас сделан как (event_type, lower(name), ts) то поможет cluster первой таблицы по этому индексу...

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

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

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

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

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

это само собой default_statistics_target=1000
кстати а где запрос? или хотябы условие соединения? там эквисоединение нормальное? типы одинаковые?
...
Рейтинг: 0 / 0
12.03.2014, 17:06:47
    #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
12.03.2014, 17:44:09
    #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
12.03.2014, 17:54:20
    #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
12.03.2014, 18:59:30
    #38584433
Ivan Durak
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
оптимизация доступа к диску
tdiff53850

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

Это да, limit.

Выбирать в отдельную таблицу пробовал, не даёт эффекта. По-моему тут беда в том, что упираюсь в скорость диска. Совет использовать кластер по индексу не подходит, потому что в реальности есть ещё один часто встречающийся запрос, в котором вместо event_cashier_name фильтруется по event_terminal. Абсолютно аналогичный запрос, для которого есть точно такой же индекс (event_type, event_ts, event_terminal). А кластеризовать можно только по одному индексу.
...
Рейтинг: 0 / 0
12.03.2014, 20:02:55
    #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
12.03.2014, 20:45:31
    #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
13.03.2014, 07:27:44
    #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
13.03.2014, 08:30:14
    #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
13.03.2014, 11:57:12
    #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
13.03.2014, 12:17:26
    #38584967
qwwq
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
оптимизация доступа к диску
[quot Maxim Boguk]йокарный бабайпропущено...


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


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


поэтому проще смириться
...
Рейтинг: 0 / 0
14.03.2014, 09:54:05
    #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
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / оптимизация доступа к диску / 21 сообщений из 21, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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