
Вот есть у меня 2 таблицы. Первая: cells, ключевое поле cellref. Вторая - cells_adj, ключевые поля cellref и targetcellref. Первая содержит описание объектов (порядка 760 тыс.), другая - определенный взаимосвязи между ними (всего порядка 11,5 млн), по типу "один ко многим" или "многие к одному".
Делаю выборку из этих таблиц...
Одна выборка проходит почти моментально (выбираю связи "один ко многим" для определенного объекта)
select c.lac as lac, c.cellid as cellid, c2.lac as targetlac, c2.cellid as targetcellid, c.bcch, c.bsic, c2.targetbcch, c2.targetbsic, adj.*
from
(select lac, cellid, cellref, omc, bcch_freq as bcch, bsic from cells where date_='2010-01-25' and omc=3 and cellref=164) c,
(select * from cells_adj where date_='2010-01-25' and cellref=164 and omc=3) adj,
(select lac, cellid, cellref, omc, bcch_freq as targetbcch, bsic as targetbsic from cells where date_='2010-01-25' and omc=3 ) c2
where adj.targetcellref=c2.cellref and c.cellref=adj.cellref</span>
Итог: выбрано 17 строк, время ~0.09с
А вторая выборка для связей "многие к одному" для того же объекта
select c.lac as lac, c.cellid as cellid, c2.lac as targetlac, c2.cellid as targetcellid, c.bcch, c.bsic, c2.targetbcch, c2.targetbsic, adj.*
from
(select lac, cellid, cellref, omc, bcch_freq as bcch, bsic from cells where date_='2010-01-25' and omc=3) c,
(select * from cells_adj where date_='2010-01-25' and targetcellref=164 and omc=3) adj,
(select lac, cellid, cellref, omc, bcch_freq as targetbcch, bsic as targetbsic from cells where date_='2010-01-25' and omc=3 and cellref=164) c2
where adj.targetcellref=c2.cellref and c.cellref=adj.cellref</span>
Итог: выбрано 17 строк, время ~33-37 с



Вопрос: почему так долго? Вроде бы, практически симметричная выборка, оба запроса должны выполняться примерно одинаковое время.
Индексы, вроде как, правильно прописаны. EXPLAIN пишет одно и то же (с точностью до отдельных обозначений). Но разница во времени выполнения в сотни раз меня "несколько напрягает".
PS. EXPLAIN выдает практически одно и то же, для обоих запросов. С точностью до названий полей.
Спустя 10 минут, 32 секунды (27.01.2010 - 16:07) sergeiss написал(а):
EXPLAIN для "короткого" запроса:
И для "длинного" запроса:
Я их как только не рассматривал...
"Nested Loop (cost=0.00..27.35 rows=1 width=76)"
" Join Filter: (public.cells.cellref = cells_adj.targetcellref)"
" -> Nested Loop (cost=0.00..16.86 rows=1 width=32)"
" -> Index Scan using cells_index on cells (cost=0.00..8.42 rows=1 width=16)"
" Index Cond: ((date_ = '2010-01-25'::date) AND (cellref = 164) AND (omc = 3))"
" Filter: (lac IS NOT NULL)"
" -> Index Scan using cells_index on cells (cost=0.00..8.42 rows=1 width=16)"
" Index Cond: ((public.cells.date_ = '2010-01-25'::date) AND (public.cells.omc = 3))"
" Filter: (public.cells.lac IS NOT NULL)"
" -> Index Scan using date_cells_adj on cells_adj (cost=0.00..10.48 rows=1 width=52)"
" Index Cond: ((cells_adj.date_ = '2010-01-25'::date) AND (cells_adj.cellref = 164) AND (cells_adj.omc = 3))"
И для "длинного" запроса:
"Nested Loop (cost=0.00..27.35 rows=1 width=76)"
" Join Filter: (public.cells.cellref = cells_adj.cellref)"
" -> Nested Loop (cost=0.00..16.86 rows=1 width=32)"
" -> Index Scan using cells_index on cells (cost=0.00..8.42 rows=1 width=16)"
" Index Cond: ((date_ = '2010-01-25'::date) AND (cellref = 164) AND (omc = 3))"
" Filter: (lac IS NOT NULL)"
" -> Index Scan using cells_index on cells (cost=0.00..8.42 rows=1 width=16)"
" Index Cond: ((public.cells.date_ = '2010-01-25'::date) AND (public.cells.omc = 3))"
" Filter: (public.cells.lac IS NOT NULL)"
" -> Index Scan using date_cells_adj on cells_adj (cost=0.00..10.48 rows=1 width=52)"
" Index Cond: ((cells_adj.date_ = '2010-01-25'::date) AND (cells_adj.targetcellref = 164) AND (cells_adj.omc = 3))"
Я их как только не рассматривал...
Спустя 1 час, 44 минуты, 50 секунд (27.01.2010 - 17:52) sergeiss написал(а):
Вобщем... После некоторых обсуждений в асе, и после активного морщенья "серого вещества" получил следующее.
Изначально индекс был сделан один, по полям (date_, cellref, targetcellref, omc).
Я пытался сделать разные индексы, в т.ч. 4 индекса (по одному полю каждый). Этот вариант был самый "тормозной": эти запросы выполялись порядка 160-170 сек каждый
В итоге пришел к тому, что сделал один индекс по 4-м полям (как и раньше), только поменял порядок: (cellref, targetcellref, date_, omc). Время выполнения этих же запросов 0.1 и 2.1 сек, что уже намного лучше. Хотя разница в 20 раз так и не понятна мне до сих пор.
Тут только осталось заметить, что меньше всего вариаций в колонке omc (всего 5; она оказалась в самом конце), побольше разных вариаций в колонке date_ (несколько десятков; на предпоследнем месте), и достаточно много разных cellref и targetcellref (по несколько тысяч каждых, в целом их количества практически равны).
Почему так - я не знаю, но "метод научного тыка" привел к такому заключению: в самом начале в индексе надо ставить те параметры, у которых больше всего разных величин. И дальше по убыванию.
Если не прав - "ткните пальцОм", в чем именно не прав
PS. Спасибо всем за активное участие в решении проблемы
Изначально индекс был сделан один, по полям (date_, cellref, targetcellref, omc).
Я пытался сделать разные индексы, в т.ч. 4 индекса (по одному полю каждый). Этот вариант был самый "тормозной": эти запросы выполялись порядка 160-170 сек каждый

В итоге пришел к тому, что сделал один индекс по 4-м полям (как и раньше), только поменял порядок: (cellref, targetcellref, date_, omc). Время выполнения этих же запросов 0.1 и 2.1 сек, что уже намного лучше. Хотя разница в 20 раз так и не понятна мне до сих пор.
Тут только осталось заметить, что меньше всего вариаций в колонке omc (всего 5; она оказалась в самом конце), побольше разных вариаций в колонке date_ (несколько десятков; на предпоследнем месте), и достаточно много разных cellref и targetcellref (по несколько тысяч каждых, в целом их количества практически равны).
Почему так - я не знаю, но "метод научного тыка" привел к такому заключению: в самом начале в индексе надо ставить те параметры, у которых больше всего разных величин. И дальше по убыванию.
Если не прав - "ткните пальцОм", в чем именно не прав

PS. Спасибо всем за активное участие в решении проблемы

Спустя 14 минут, 32 секунды (27.01.2010 - 18:06) olgatcpip написал(а):
Понятно, вот это сегодня же прпытаюсь применить !
Спасибо за статью. очень позновательно!
Спасибо за статью. очень позновательно!
Спустя 5 минут, 35 секунд (27.01.2010 - 18:12) sergeiss написал(а):
Цитата (olgatcpip @ 27.01.2010 - 19:06) |
Спасибо за статью |
Это статья??? Это моя головная боль

Спустя 12 минут, 28 секунд (27.01.2010 - 18:24) sergeiss написал(а):
И еще "довесочек". Дооптимизировал, похоже, до самого конца.
Во втором запросе поменял 2 строки...
Было:
Стало:
И хотите верьте, хотите - не верьте, но время выполнения этого запроса стало также на уровне 0.1-0.2 сек!
(далее выполняется танец с бубном вокруг компа)
И тому можно найти логичное объяснение. Первый подзапрос (первый по порядку написания) выдает меньше строк, чем третий. А привязка идет, как я понимаю, к первому подзапросу. В итоге просто "тупо" обрабатывается меньше данных. Вроде бы логично, но раньше не особо и задумывался над такими тонкостями.
Далее попробовал "испортить" индексы (написал "всё наоборот") - нет, чудес не бывает. Бывают только дикие чудеса... Бывший быстрый запрос стал более медленным, а "новый" запрос так и остался быстрым. Вернул индексы обратно - всё стало ОК.
Тему не закрываю, мало ли, вдруг еще на порядок уменьшу время выборки
PS. Это не статья, а скорее "лабораторная работа".
PPS. И не говорите теперь, что "от перемены мест слагаемых сумма не меняется".
Во втором запросе поменял 2 строки...
Было:
select c.lac as lac, c.cellid as cellid, c2.lac as targetlac, c2.cellid as targetcellid, c.bcch, c.bsic, c2.targetbcch, c2.targetbsic, adj.*
from
(select lac, cellid, cellref, omc, bcch_freq as bcch, bsic from cells where date_='2010-01-25' and omc=3) c,
(select * from cells_adj where date_='2010-01-25' and targetcellref=164 and omc=3) adj,
(select lac, cellid, cellref, omc, bcch_freq as targetbcch, bsic as targetbsic from cells where date_='2010-01-25' and omc=3 and cellref=164) c2
where adj.targetcellref=c2.cellref and c.cellref=adj.cellref</span>
Стало:
select c.lac as lac, c.cellid as cellid, c2.lac as targetlac, c2.cellid as targetcellid, c.bcch, c.bsic, c2.targetbcch, c2.targetbsic, adj.*
from
(select lac, cellid, cellref, omc, bcch_freq as targetbcch, bsic as targetbsic from cells where date_='2010-01-25' and omc=3 and cellref=164) c2,
(select * from cells_adj where date_='2010-01-25' and targetcellref=164 and omc=3) adj,
(select lac, cellid, cellref, omc, bcch_freq as bcch, bsic from cells where date_='2010-01-25' and omc=3) c
where adj.targetcellref=c2.cellref and c.cellref=adj.cellref</span>
И хотите верьте, хотите - не верьте, но время выполнения этого запроса стало также на уровне 0.1-0.2 сек!



И тому можно найти логичное объяснение. Первый подзапрос (первый по порядку написания) выдает меньше строк, чем третий. А привязка идет, как я понимаю, к первому подзапросу. В итоге просто "тупо" обрабатывается меньше данных. Вроде бы логично, но раньше не особо и задумывался над такими тонкостями.
Далее попробовал "испортить" индексы (написал "всё наоборот") - нет, чудес не бывает. Бывают только дикие чудеса... Бывший быстрый запрос стал более медленным, а "новый" запрос так и остался быстрым. Вернул индексы обратно - всё стало ОК.
Тему не закрываю, мало ли, вдруг еще на порядок уменьшу время выборки

PS. Это не статья, а скорее "лабораторная работа".
PPS. И не говорите теперь, что "от перемены мест слагаемых сумма не меняется".
Спустя 5 дней, 7 часов, 8 минут, 10 секунд (5.02.2010 - 01:32) olgatcpip написал(а):
Хочу поделиться моим опытом.
И был у меня запросище, пример которого приводить не буду, ивыполнялся он аж целых 3 МИНУТЫ!
1 - что мне помогло это чтение мануала по постгресу, ибо моя БД имено на нем стоит.
короче, в запросе был вызов функций. вот у них то я и уменьшила cost. Тут главное не ринуться всем функциям изменять этот параметр.
и после этого мой запросище стал выполняться аж 50-55 секунд ПРОГРЕСС!
2 - далее я колупалась с индексами под руководством Сергея, спасибо ему большое, что не только не отправил читать библию, но и активно помогал.
В моем случае индексы не сильно помогли, так как выполнялось на столько много лишних действий, что боюсь даже вспоминать.
3 - Пока я боролась с индексами, обнаружила, что
есть у меня такая строка в запросе
И уже стало выполняться 6-[s]10 секунд
3 - Избавляюсь от избыточности , которую сама и создала.
по предворительным подсчетам должно ещё на несколько сек сократиться
4 - ещё дернула сис админа. чтобы тот настройки сервера поменял, по рекомендациям от сюда, но что-то разницы я не заметила
И был у меня запросище, пример которого приводить не буду, и
1 - что мне помогло это чтение мануала по постгресу, ибо моя БД имено на нем стоит.
короче, в запросе был вызов функций. вот у них то я и уменьшила cost. Тут главное не ринуться всем функциям изменять этот параметр.
и после этого мой запросище стал выполняться аж 50-55 секунд ПРОГРЕСС!
2 - далее я колупалась с индексами под руководством Сергея, спасибо ему большое, что не только не отправил читать библию, но и активно помогал.
В моем случае индексы не сильно помогли, так как выполнялось на столько много лишних действий, что боюсь даже вспоминать.
3 - Пока я боролась с индексами, обнаружила, что
есть у меня такая строка в запросе
where func(id)=1и дабы много раз не вызывалась эта функия, я добавила в таблицу поле=func(id)
И уже стало выполняться 6-[s]10 секунд
3 - Избавляюсь от избыточности , которую сама и создала.
по предворительным подсчетам должно ещё на несколько сек сократиться
4 - ещё дернула сис админа. чтобы тот настройки сервера поменял, по рекомендациям от сюда, но что-то разницы я не заметила

Спустя 17 часов, 35 минут, 57 секунд (5.02.2010 - 19:08) olgatcpip написал(а):
А вот вам для сравнения мой опыт.
запрос 1
и запрос 2
первый выполняется 10 секунд
второй 2 секунды
это сравнение, при отсутствии дополнительных индексов (т.е. PK и FK таки есть)
Этот эффект я не могу объяснить, ещё не доросла.
сейчас эксперементирю с вариациями индексов.
запрос 1
SELECT DISTINCT ON (s.id_site) p.id, s.id_site,p.rank
FROM
( select DISTINCT ON (id_link) id, id_link, ts_rank(fts_modif_content, query) as rank
from webmaster.pages,plainto_tsquery('ru','нефть') query
WHERE fts_modif_content @@ query and ts_rank(fts_modif_content, query)>0
and may_buy=1 and is_del = FALSE
) AS p
INNER JOIN (select DISTINCT ON (id_site) id_site,id_link
from webmaster.links where is_del = FALSE )
AS l ON l.id_link=p.id_link
INNER JOIN(select id_site,id_cat from webmaster.sites
WHERE is_del = FALSE AND i_status = 3 )
AS s ON l.id_site = s.id_site
INNER JOIN public.tbl_sub_rubric AS sr ON sr.id = s.id_cat
INNER JOIN webmaster.tbl_site_info AS si ON s.id_site = si.id_site
limit 10 offset 0
и запрос 2
SELECT DISTINCT ON (s.id_site) p.id, s.id_site,
ts_rank(p.fts_content, query) AS rank
FROM
webmaster.pages AS p
INNER JOIN webmaster.links AS l ON l.id_link=p.id_link
INNER JOIN webmaster.sites AS s ON l.id_site = s.id_site
INNER JOIN public.tbl_sub_rubric AS sr ON sr.id = s.id_cat
INNER JOIN webmaster.tbl_site_info AS si ON s.id_site = si.id_site,
plainto_tsquery('ru','нефть') query
WHERE
p.fts_content @@ query AND s.is_del = FALSE AND
p.is_del = FALSE AND
l.is_del = FALSE AND
p.may_buy=1 AND
s.i_status = 3
limit 10 offset 0
первый выполняется 10 секунд
второй 2 секунды
это сравнение, при отсутствии дополнительных индексов (т.е. PK и FK таки есть)
Этот эффект я не могу объяснить, ещё не доросла.
сейчас эксперементирю с вариациями индексов.
Спустя 1 месяц, 2 дня, 50 минут, 48 секунд (7.03.2010 - 19:59) olgatcpip написал(а):
Ещё могу дать совет. Если У вас полнотекстовый поиск, то нужно индекс поставить на вектор. Выглядеть это будет примерно так:
у меня запрос с (6,360 sec) ускорился до (2,828 sec)
выборка была только 10 строк с сортировкой. А count стал с 6-8 секунд до пол секунды... летает! это я в сравнении с даными 3х месяцев говорю тама 3 минуты это все!
CREATE INDEX "field_idx" ON "shema"."table"где ts_vector_field типа TSVECTOR в таблице tables
USING gin ("ts_vector_field");
у меня запрос с (6,360 sec) ускорился до (2,828 sec)
выборка была только 10 строк с сортировкой. А count стал с 6-8 секунд до пол секунды... летает! это я в сравнении с даными 3х месяцев говорю тама 3 минуты это все!
_____________
* Хэлп по PHP
* Описалово по JavaScript
* Хэлп и СУБД для PostgreSQL
* Обучаю PHP, JS, вёрстке. Интерактивно и качественно. За разумные деньги.
* "накапливаю умение телепатии" (С) и "гуглю за ваш счет" (С)
