powered by simpleCommunicator - 2.0.56     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Индексы на больших объёмах
22 сообщений из 22, страница 1 из 1
Индексы на больших объёмах
    #32545709
aev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
aev
Гость
Имеется БД в которой более 60 млн. записей.

Table "public.tr_email"
Column | Type | Modifiers
-------------+------------------------+----------------------------------------------------------
id | integer | not null default nextval('public.tr_email_id_seq'::text)
category_id | integer | not null
address | character varying(255) | not null
is_active | boolean | not null default true
Indexes:
"tr_email_pkey" primary key, btree (id)
"tr_email_address_key" unique, btree (address)
"tr_emailndx1" btree (category_id, is_active)
Foreign-key constraints:
"$1" FOREIGN KEY (category_id) REFERENCES tr_email_category(id) ON DELETE CASCADE

Почему простой select (приведён ниже) не использует индекс?

EXPLAIN SELECT * FROM tr_email WHERE category_id = 1;
QUERY PLAN
----------------------------------------------------------------------
Seq Scan on tr_email (cost=0.00..1327459.55 rows=12259563 width=33)
Filter: (category_id = 1)
(2 rows)

VACUUM ANALYZE делал. Пробовал принудительно использовать индекс (SET enable_seqscan TO OFF) - время работы получается больше. В чём дело?
...
Рейтинг: 0 / 0
Индексы на больших объёмах
    #32545747
Wireless
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
I. Попробуй сделать
1. ALTER TABLE tr_email ALTER category_id SET STATISTICS 500;
2. ANALYZE tr_email
где "500" число порядка select count(distinct category_id) from tr_email

II. Если SELECT count(*) FROM tr_email WHERE category_id = 1 ;
составляет значительную часть от общего числа записей из tr_email,
то seq_scan может быть действительно быстрее indexscan.

Ш. Если ты уверен, что оптимизатор ведет себя неверно и тебе точно
нужно использовать в этом запросе индекс, то сделай перед этим запросом
Код: plaintext
set enable_Seqscan=false;

P.S. PG какой версии ?
...
Рейтинг: 0 / 0
Индексы на больших объёмах
    #32545763
aev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
aev
Гость
select count(distinct category_id) from tr_email
Число категории невелико (максимум 25)

Если SELECT count(*) FROM tr_email WHERE category_id = 1;
составляет значительную часть от общего числа записей из tr_email,
то seq_scan может быть действительно быстрее indexscan.


Всего: 64 млн. записей, и 10 категориий. Распределение такое:
1) 12,2 млн
2) 1,3 млн
3) 23 млн
4) 2,3 млн
5) 13,6 млн
6) 43 тыс
7) 590 тыс
8) 10,2 млн
9) 900 тыс

Когда я отключал seqscan, то оптимизатор показывал большее время выполнения запроса.

PostgreSQL 7.4
...
Рейтинг: 0 / 0
Индексы на больших объёмах
    #32545775
aev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
aev
Гость
И ещё:
Если категория содержит менее 10 млн. записей, то используется индекс. Если больше - то нет. Так и должно быть? Время выполнения около 30 минут!!!
...
Рейтинг: 0 / 0
Индексы на больших объёмах
    #32545793
Wireless
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да, что-то медленно. Что говорят команды iostat, top во время
выполненеия запроса?
Сколько Мб физически таблица занимает?
Винты медленные, какой сервер? Могу посоветовать поставить RAID.

Создай N таблиц, где N - число категорий.
tr_email_1, tr_email_2, tr_email_3 и т.д.
И запросы соотв-м образом формировать.
Это убогий вариант того, что в Oracle называется partioning.
Индекс по полю categoty_id здесь вообще не нужен :)

И еще, пересоздай таблицу с опцией WITHOUT OIDS.
...
Рейтинг: 0 / 0
Индексы на больших объёмах
    #32545915
aev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
aev
Гость
Характеристики машины:
Dual Xeon 2.4Ghz, 2GB Ram, mirrored 80GB HDDs

Под Shared Memory я выделил 256 MB.
Top показывает, что при выполнении selecta от процессора используется 10-30%, от памяти 13% (т.е. вся выделенная под Shared Memory)

БД занимает 9GB (все таблицы кроме данной пустые)

Идея с созданием таблиц для каждой категории не подходит, т.к. придётся очень много кода переписывать.
...
Рейтинг: 0 / 0
Индексы на больших объёмах
    #32545941
Sad Spirit
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
таблица охрененно напоминает базу адресов для спама. давить ублюдков.
...
Рейтинг: 0 / 0
Индексы на больших объёмах
    #32545954
aev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
aev
Гость
если бы спам............. статистика ГТС
...
Рейтинг: 0 / 0
Индексы на больших объёмах
    #32545987
Wireless
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
авторИдея с созданием таблиц для каждой категории не подходит, т.к. придётся очень много кода переписывать.
а жаль, это бы здорово помогло...

Попробуй сделать CLUSTER tr_emailndx1 ON tr_email .

Над category_id у тебя один индекс по 2м полям.
"tr_emailndx1" btree (category_id, is_active)
Посмотри не станет ли лучше если будет отдельный индекс только
по полю category.

авторХарактеристики машины:
Подключи еще один винт и перемести туда файл-индекс,
а на старом месте сделай symlink.
И подключи еще один винт, разместив там WAL,
...эээ, здесь хотел сказать временное табличное пространство, но в PG
этого нет:), но думаю в PG как-то тоже можно заставить создавать
временные файлы (кот-ые исп-ся например при больших сортировках)
в указанном месте.
Монтируй файловые системы с опцией noatime, в режиме soft updates.

И еще, если у тебя запросы в основном идут к category_id=1,
то можешь сделать условный индекс только для этой категории:
CREATE INDEX .... WHERE category_id=1
и вообще говоря, можешь сделать несколько условных индексов для
каждой категории
CREATE INDEX tr_email_categ_1 . . . . . WHERE category_id=1
CREATE INDEX tr_email_categ_2 . . . . . WHERE category_id=2
надо смотреть, тоже должно помочь для выборок,
но за счет замедления INSERT/UPDATE...
...
Рейтинг: 0 / 0
Индексы на больших объёмах
    #32545995
Wireless
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
> напоминает базу адресов для спама.
ну, думаю, если все заработает, aev мне сделает одну рассылку на Штаты?
...
Рейтинг: 0 / 0
Индексы на больших объёмах
    #32546020
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Приведите пожалуйста результаты выполнения следующих команд:

SET enable_seqscan TO on;
EXPLAIN ANALYZE SELECT * FROM tr_email WHERE category_id = 1;

SET enable_seqscan TO off;
EXPLAIN ANALYZE SELECT * FROM tr_email WHERE category_id = 1;
...
Рейтинг: 0 / 0
Индексы на больших объёмах
    #32546037
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Еще вопрос: что вы далее делаете с результатом запроса, состоящим из 12 миллионов строк? Если еще как-то фильтруете, то может быть сделать эту фильтрацию в самом запросе? Если вычисляете какие-то групповые функции, то может быть их вычислить в запросе?
...
Рейтинг: 0 / 0
Индексы на больших объёмах
    #32546236
aev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
aev
Гость
SET enable_seqscan TO on;
EXPLAIN ANALYZE SELECT * FROM tr_email WHERE category_id = 1;

QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------
Seq Scan on tr_email (cost=0.00..1327459.55 rows=12259563 width=33) (actual time=0.113..2717358.453 rows=12189810 loops=1)
Filter: (category_id = 1)
Total runtime: 2731638.130 ms

SET enable_seqscan TO off;
EXPLAIN ANALYZE SELECT * FROM tr_email WHERE category_id = 1;

QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------
Index Scan using tr_emailndx1 on tr_email (cost=0.00..34687630.64 rows=12259563 width=33) (actual time=38.962..245449.002 rows=12189810 loops=1)
Index Cond: (category_id = 1)
Total runtime: 281099.570 ms

Получается так что оптимизатор неправильно выбирает план запроса. Как сделать чтобы он использовал индекс (без принудительного enable_seqscan to off)?

Еще вопрос: что вы далее делаете с результатом запроса, состоящим из 12 миллионов строк? Если еще как-то фильтруете, то может быть сделать эту фильтрацию в самом запросе? Если вычисляете какие-то групповые функции, то может быть их вычислить в запросе?

Здесь должны производиться кое-какие подсчёты и сбор статистики, но это не важно - select подправится. Сейчас вопрос стотит так, почему запрпос по индексированному полю занимает так много времени?!
...
Рейтинг: 0 / 0
Индексы на больших объёмах
    #32546267
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Получается так что оптимизатор неправильно выбирает план запроса.

Почему же неправильно. Для этого запроса он поступил правильно, хотя бы потому что 2731638.130 ms < 281099.570 ms.

Как сделать чтобы он использовал индекс (без принудительного enable_seqscan to off)?

Для чего? Мне кажется, что этого делать не нужно, так как в этом запросе seq_scan имеет примерно одинаковое с index_scan-ом время.

почему запрпос по индексированному полю занимает так много времени?!

Потому что условию в WHERE удовлетворяют очень много строк.
...
Рейтинг: 0 / 0
Индексы на больших объёмах
    #32546279
aev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
aev
Гость
Почему же неправильно. Для этого запроса он поступил правильно, хотя бы потому что 2731638.130 ms < 281099.570 ms.

2 731 638.130 ms > 281 099.570 ms

Наверное порядком промазал..............
...
Рейтинг: 0 / 0
Индексы на больших объёмах
    #32546395
wbear
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
а explain analyze на этотже запрос (с/без index_scana) что говори?
...
Рейтинг: 0 / 0
Индексы на больших объёмах
    #32546418
aev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
aev
Гость
Я же привёл пример того что говорит explain analyze (см. чуть выше)
...
Рейтинг: 0 / 0
Индексы на больших объёмах
    #32546478
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
порядком промазал

Точно. Прошу прощения за невнимательность. И текст моего предыдущего поста не принимать во внимание, так как он не имеет силы из-за этой моей ошибки.

Нам тоже приходится бороться с постгресом на поле выбора execution планов. Однако того, чтобы оценка постгреса отличалась от реальности в 300 раз, наблюдать не доводилось. (1327459.55/2717358.453) / (34687630.64/245449.002) = 0.0034566945089819 ~= 1/300.

Попробуйте изменить значения Planner Cost Constants (пункт 16.4.4.2. в документации), в особенности, если мне не изменяет память, играет роль random_page_cost. В гугле и мэйл-листах postgresql.org есть обсуждения random_page_cost.

Попробуйте CLUSTER-изовать таблицу по индексу tr_emailndx1. Однако, эту операцию придется выполнять регулярно a-la vacuum analyze. :-(

Если успех не достигнут, посмотрите на статистику собранную vacuumanalyze-ом об этой таблице и в сорцы планировщика постгреса. :-(

Возможно, корень вашей проблемы в том же, о чем я написал в рассылку после двухдневного копания в сорцах: корреляция внутри дисковой страницы вместо глобальной?
...
Рейтинг: 0 / 0
Индексы на больших объёмах
    #32546590
YuSha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
попробуй вот так
WHERE category_id = '1'
или так
WHERE category_id = 1::integer

я тоже наступил на эти грабли
похоже, что Postgre преобразование типов выполняет не в ту сторону (category_id преобразуется в тип константы 1, а не наоборот, как хотелось бы)

по крайней мере после такого синтаксиса у меня все начало летать (в таблице с несколькими млн записей вместо 30 секунд запрос выполняется доли секунды)
...
Рейтинг: 0 / 0
Индексы на больших объёмах
    #32547319
YuSha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Разогреваю тему:
имеем

# \d acct
Table "public.acct"
Column | Type | Modifiers
---------------------+--------------------------------+----------------------------------------------------------
acctid | bigint | not null default nextval('public.acct_acctid_seq'::text)
...
Indexes: acct_pkey primary key btree (acctid),
...

в чем разница между запросами?
# explain select * from acct where acctid = 35000000;
QUERY PLAN
-----------------------------------------------------------
Seq Scan on acct (cost=0.00..155269.20 rows=1 width=442)
Filter: (acctid = 35000000)

# explain select * from acct where acctid = '35000000';
QUERY PLAN
------------------------------------------------------------------------
Index Scan using acct_pkey on acct (cost=0.00..3.49 rows=1 width=442)
Index Cond: (acctid = 35000000::bigint)

# explain select * from acct where acctid = 3500000::bigint;
QUERY PLAN
------------------------------------------------------------------------
Index Scan using acct_pkey on acct (cost=0.00..3.49 rows=1 width=442)
Index Cond: (acctid = 3500000::bigint)
...
Рейтинг: 0 / 0
Индексы на больших объёмах
    #32547510
Sad Spirit
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
YuSha
пальцем в ж...
товарищ же в первом сообщении привёл схему, у него поле integer, а не bigint.
...
Рейтинг: 0 / 0
Индексы на больших объёмах
    #32547698
eddie
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
честно говоря очень странно....

по индексу просматривается 43.4 тысяч записей в секунду (12 миллионов за 281 сек), без индекса 23.4 тысяч записей в секунду (64 миллиона записей за 2 731 сек) - при просмотре по индексу просматриваются только нужные записи, иначе вся таблица.
Теория же учит - при последовательном чтении перемещений головок гораздо меньше, чем при переборе по индексу - поэтому должно быть наоборот....

соответственно планировщик ведёт себя неадекватно такой реальности, его можно немного "подправить" уменьшив random_page_cost (кстати а какая у вас дисковая подсистема?), но в любом случае надо искать объяснение такому странному поведению...

вариант 0: не учтено влияние дискового кэша операционной системы (первый проход загружает данные в кэш, второй же быстро их оттуда достает). решение - запустить каждый запрос (без seq_scan/с seq_scan) по 3 раза подряд, первый результат проигнорировать, между вторым и третьим взять среднее. маловероятно, т.к. объем базы хоть и не на порядок, но все-таки существенно превосходит размер ram

вариант 1: postgesql очень неэффективно обрабатывает условие "category_id = 1".
можно попробовать в частности 1::integer (хотя очень сильно сомневаюсь)

больше пока вариантов причин такого аномального поведения не видется

в любом случае мне кажется стоит провести дополнительные эксперименты и попробовать сообщить в pgsql-performance - думаю помогут (а если проблемы в самом pgsql - может и подправят к 7.5)
...
Рейтинг: 0 / 0
22 сообщений из 22, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Индексы на больших объёмах
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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