powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Медленный SELECT по индексам
9 сообщений из 9, страница 1 из 1
Медленный SELECT по индексам
    #38738154
Stan_1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый день!

Не могу понять, в чем проблема. Есть вот такой запрос на таблице в 25 млн. строк.
Код: plsql
1.
SELECT myid FROM big_table  WHERE is_processed=false GROUP BY myid LIMIT 500



Его EXPLAIN показывает следующее:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
Limit  (cost=0.00..25338.26 rows=500 width=16) (actual time=324597.038..324618.080 rows=500 loops=1)
  Buffers: shared hit=10755736 read=202114
  ->  Group  (cost=0.00..7756650.96 rows=153062 width=16) (actual time=324597.037..324618.033 rows=500 loops=1)
        Buffers: shared hit=10755736 read=202114
        ->  Index Scan using big_table_myid_idx on big_table  (cost=0.00..7696583.61 rows=24026943 width=16) (actual time=324597.033..324616.877 rows=20696 loops=1)
              Filter: (NOT is_processed)
              Rows Removed by Filter: 11117739
              Buffers: shared hit=10755736 read=202114
Total runtime: 324618.167 ms



Понятно, что он шарится по диску (shared_buffers установлены в 8 Гбайт), поскольку фактически перебирает всю таблицу целиком. Но почему он перебирает все записи на индексированной таблице?

Как можно оптимизировать подобный запрос?

Заранее спасибо
...
Рейтинг: 0 / 0
Медленный SELECT по индексам
    #38738163
/\/\/\/\/\/\
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Stan_1,

Может быть подойдет такой запрос:

Код: sql
1.
2.
3.
4.
5.
SELECT DISTINCT
  myid
FROM big_table
WHRERE is_processed = FALSE
LIMIT 500;



Так же попробуйте составной индекс:
Код: sql
1.
CREATE INDEX ix_big_table_1 ON big_table (myid, is_processed);
...
Рейтинг: 0 / 0
Медленный SELECT по индексам
    #38738267
Troglodit
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Я не уверен насчет Postgre,но у вас is_processed принимает только 2 значения. Если is_processed=false > 20% строк,то индекс по этому полю не имеет смысла, в итоге будет перебор всех записей.
Проще ввести суррогатное вычисляемое поле с индексом, либо индекс по функции где уникальных значений было бы больше , либо маркер записей,который в ходят в первые 500(как вариант материализованная view), тогда индекс отлично будет работать.
...
Рейтинг: 0 / 0
Медленный SELECT по индексам
    #38738467
Ivan Durak
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Stan_1Добрый день!

Не могу понять, в чем проблема. Есть вот такой запрос на таблице в 25 млн. строк.
Код: plsql
1.
SELECT myid FROM big_table  WHERE is_processed=false GROUP BY myid LIMIT 500



Его EXPLAIN показывает следующее:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
Limit  (cost=0.00..25338.26 rows=500 width=16) (actual time=324597.038..324618.080 rows=500 loops=1)
  Buffers: shared hit=10755736 read=202114
  ->  Group  (cost=0.00..7756650.96 rows=153062 width=16) (actual time=324597.037..324618.033 rows=500 loops=1)
        Buffers: shared hit=10755736 read=202114
        ->  Index Scan using big_table_myid_idx on big_table  (cost=0.00..7696583.61 rows=24026943 width=16) (actual time=324597.033..324616.877 rows=20696 loops=1)
              Filter: (NOT is_processed)
              Rows Removed by Filter: 11117739
              Buffers: shared hit=10755736 read=202114
Total runtime: 324618.167 ms



Понятно, что он шарится по диску (shared_buffers установлены в 8 Гбайт), поскольку фактически перебирает всю таблицу целиком. Но почему он перебирает все записи на индексированной таблице?

Как можно оптимизировать подобный запрос?

Заранее спасибо
Есть шустрый но не гарантированный вариант:


SELECT myid FROM
(
SELECT myid,is_processed
FROM big_table LIMIT 50000 (--ставь число строк в которе попадет 500 уникальных)
) sub
WHERE is_processed=false
GROUP BY myid LIMIT 500;

Тут будет скан только 50к строк из индекса что на порядки меньше всей таблицы
...
Рейтинг: 0 / 0
Медленный SELECT по индексам
    #38738475
Ivan Durak
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
или даже так

SELECT myid FROM
(
SELECT myid,is_processed
FROM big_table
WHERE is_processed=false
LIMIT 50000 (--ставь число строк в которе попадет 500 уникальных)
) sub
GROUP BY myid
LIMIT 500;
...
Рейтинг: 0 / 0
Медленный SELECT по индексам
    #38738704
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
...
Рейтинг: 0 / 0
Медленный SELECT по индексам
    #38738784
Stan_1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
/\/\/\/\/\/\Stan_1,

Может быть подойдет такой запрос:

Код: sql
1.
2.
3.
4.
5.
SELECT DISTINCT
  myid
FROM big_table
WHRERE is_processed = FALSE
LIMIT 500;



Нет, ситуация такая же. Но здесь прав Troglodit в письме ниже (и причина на поверхности). Если индекс на 80% состоит из одного значения, то Index Scan практически превращается в Seq Scan

/\/\/\/\/\/\Stan_1,
Так же попробуйте составной индекс:
Код: sql
1.
CREATE INDEX ix_big_table_1 ON big_table (myid, is_processed);



А это я обязательно попробую, и потом отпишусь. Самому интересно стало. :)
...
Рейтинг: 0 / 0
Медленный SELECT по индексам
    #38738796
Alexius
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Stan_1,

имеет смысл попробовать создать такой индекс:
Код: sql
1.
create index big_table_is_myid_partial_idx on big_table (myid) where is_processed = false;
...
Рейтинг: 0 / 0
Медленный SELECT по индексам
    #38739095
Stan_1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ну все, вроде сделал следующим образом. Ввел столбец shard_id, и сделал составной индекс: shard_id, is_processed. Затем дал каждой 300 тыс. записей свое значение shard_id. И все стало работать быстро.

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
Limit  (cost=18575.96..18576.46 rows=500 width=16) (actual time=196.315..196.448 rows=500 loops=1)
  Buffers: shared hit=12296
  ->  HashAggregate  (cost=18575.96..18577.25 rows=1292 width=16) (actual time=196.313..196.413 rows=500 loops=1)
        Buffers: shared hit=12296
        ->  Index Scan using big_table_shard_id_idx on big_table  (cost=0.00..18037.21 rows=215501 width=16) (actual time=0.028..130.702 rows=185881 loops=1)
              Index Cond: (shard_id = 10)
              Filter: (NOT is_processed)
              Rows Removed by Filter: 114119
              Buffers: shared hit=12296
Total runtime: 196.867 ms
...
Рейтинг: 0 / 0
9 сообщений из 9, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Медленный SELECT по индексам
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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