У меня есть таблица с несколькими миллионами строк, в которую я постоянно вставляю новые данные, а также извлекаю.
Структура:
('orig_city', 'INTEGER NOT NULL'),
('dest_city', 'INTEGER NOT NULL'),
('dep_date', 'DATE NOT NULL'),
('orig_city_code', 'TEXT NOT NULL'),
('dest_city_code', 'TEXT NOT NULL'),
('trip_id', 'TEXT'),
('agent', 'TEXT'),
('source', 'TEXT'),
('price', 'INTEGER'),
('deep_link', 'TEXT'),
('ts', 'TIMESTAMP(0) WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP'),
('PRIMARY KEY', '(trip_id, agent, source)')
с idx_trips_201809
= 'orig_city, dest_city, dep_date'
Обычно он работает достаточно хорошо, но я понял, что время от времени появляются SELECT
запросы, которые слишком медленные.
Я видел, что пару раз это заняло даже больше 40 секунд. К сожалению, я не смог скопировать их для команды EXPLAIN
.
Все команды выполняются через python. Вот пример.
Запрос:
sql_query = """SELECT * FROM trips_201809 WHERE (orig_city = %s OR dest_city = %s) AND dep_date = %s"""
vals = (91, 279, 2018-09-21)
cur.execute(sql_query, vals)
fetched = cur.fetchall()
, где 2018-09-21 - это datetime.date
объект.
EXPLAIN ANALYZE
показывает:
('Bitmap Heap Scan on trips_201809 (cost=45576.77..50231.46 rows=2430 width=769) (actual time=1055.970..5993.580 rows=2597 loops=1)',)
(" Recheck Cond: (((orig_city = 91) AND (dep_date = '2018-09-21'::date)) OR ((dest_city = 279) AND (dep_date = '2018-09-21'::date)))",)
(' Heap Blocks: exact=1199',)
(' -> BitmapOr (cost=45576.77..45576.77 rows=2438 width=0) (actual time=1038.635..1038.635 rows=0 loops=1)',)
(' -> Bitmap Index Scan on idx_trips_201809 (cost=0.00..593.63 rows=1824 width=0) (actual time=22.119..22.119 rows=1605 loops=1)',)
(" Index Cond: ((orig_city = 91) AND (dep_date = '2018-09-21'::date))",)
(' -> Bitmap Index Scan on idx_trips_201809 (cost=0.00..44982.90 rows=614 width=0) (actual time=1016.514..1016.514 rows=1004 loops=1)',)
(" Index Cond: ((dest_city = 279) AND (dep_date = '2018-09-21'::date))",)
('Planning time: 0.927 ms',)
('Execution time: 5994.242 ms',)
-
('Bitmap Heap Scan on trips_201809 (cost=45576.77..50231.46 rows=2430 width=769) (actual time=2923.961..2984.264 rows=2597 loops=1)',)
(" Recheck Cond: (((orig_city = 91) AND (dep_date = '2018-09-21'::date)) OR ((dest_city = 279) AND (dep_date = '2018-09-21'::date)))",)
(' Heap Blocks: exact=1199',)
(' -> BitmapOr (cost=45576.77..45576.77 rows=2438 width=0) (actual time=2923.785..2923.785 rows=0 loops=1)',)
(' -> Bitmap Index Scan on idx_trips_201809 (cost=0.00..593.63 rows=1824 width=0) (actual time=1.818..1.818 rows=1605 loops=1)',)
(" Index Cond: ((orig_city = 91) AND (dep_date = '2018-09-21'::date))",)
(' -> Bitmap Index Scan on idx_trips_201809 (cost=0.00..44982.90 rows=614 width=0) (actual time=2921.966..2921.966 rows=1004 loops=1)',)
(" Index Cond: ((dest_city = 279) AND (dep_date = '2018-09-21'::date))",)
('Planning time: 0.731 ms',)
('Execution time: 2984.482 ms',)
-
('Bitmap Heap Scan on trips_201809 (cost=45576.77..50231.46 rows=2430 width=769) (actual time=231.375..233.616 rows=2598 loops=1)',)
(" Recheck Cond: (((orig_city = 91) AND (dep_date = '2018-09-21'::date)) OR ((dest_city = 279) AND (dep_date = '2018-09-21'::date)))",)
(' Heap Blocks: exact=1200',)
(' -> BitmapOr (cost=45576.77..45576.77 rows=2438 width=0) (actual time=231.222..231.222 rows=0 loops=1)',)
(' -> Bitmap Index Scan on idx_trips_201809 (cost=0.00..593.63 rows=1824 width=0) (actual time=1.781..1.781 rows=1605 loops=1)',)
(" Index Cond: ((orig_city = 91) AND (dep_date = '2018-09-21'::date))",)
(' -> Bitmap Index Scan on idx_trips_201809 (cost=0.00..44982.90 rows=614 width=0) (actual time=229.440..229.440 rows=1005 loops=1)',)
(" Index Cond: ((dest_city = 279) AND (dep_date = '2018-09-21'::date))",)
('Planning time: 0.665 ms',)
('Execution time: 233.778 ms',)
Я вижу, что проблема в исполнении, а не в планировании. Но я не могу выяснить, что именно делает его медленным.
Почему времена выполнения такие переменные?
И как я мог избежать этого иногда так долго?
Дополнительная информация по запросу в комментариях.
Селективность для типичного запроса:
dep_date
: 3%
orig_city
: от 0,1 до 1%
dest_city
: от 0,1 до 1%
Указатель, упомянутый в планах, - это тот, который я объяснил в начале вопроса. Я отредактировал это, чтобы сделать его более понятным
В этой таблице, которая на данный момент является критической, около 3% строк будет выбрано на определенную дату. Тем не менее, у меня есть другие подобные таблицы, где этот% будет также между 0,1 - 1%.
Редактировать
Добавление индекса dep_date, orig_city, dest_city
улучшило скорость выборки. Тем не менее, это все еще не так быстро, как я ожидал. Любые дополнительные предложения приветствуются.
('Bitmap Heap Scan on trips_201809 (cost=1326.19..13315.79 rows=6432 width=772) (actual time=553.464..1273.092 rows=6577 loops=1)',)
(" Recheck Cond: (((dep_date = '2018-09-21'::date) AND (orig_city = 353)) OR ((dep_date = '2018-09-21'::date) AND (dest_city = 106)))",)
(' Heap Blocks: exact=2010',)
(' -> BitmapOr (actual time=552.436..552.436 rows=0 loops=1)',)
(' -> Bitmap Index Scan on idx_trp_201809 (cost=0.00..27.56 rows=2739 width=0) (actual time=0.300..0.300 rows=2136 loops=1)',)
(" Index Cond: ((dep_date = '2018-09-21'::date) AND (orig_city = 353))",)
(' -> Bitmap Index Scan on idx_trp_201809 (cost=0.00..1297.99 rows=3771 width=0) (actual time=552.134..552.134 rows=4926 loops=1)',)
(" Index Cond: ((dep_date = '2018-09-21'::date) AND (dest_city = 106))",)
('Planning time: 100.031 ms',)
('Execution time: 1273.483 ms',)