Оптимизация запросов - PullRequest
       11

Оптимизация запросов

0 голосов
/ 07 января 2011

Это мой текущий запрос, он работает, но он медленный:

    SELECT row, MIN(flg) ||' to ' ||Max (flg) as xyz , avg(amt_won), count(*)
FROM(
SELECT (ROW_NUMBER() OVER (ORDER BY flg))*100/
(SELECT  count(*)+100 as temprow FROM temporary_six_max) as row, flg, amt_won
FROM temporary_six_max 
    JOIN (
    SELECT id_player AS pid,  avg(flg_vpip::int)  AS flg 
    FROM temporary_six_max
    GROUP BY id_player 
    ) AS auxtable
    ON pid = id_player
) as auxtable2
group by 1
order by 1;

Я группирую в фиксированном (или почти фиксированном) количестве 100 диапазонов, упорядоченных по avg (flg_vpip), сгруппированных по id_player.

Здесь я вставил результаты на случай, если это поможет понять: https://spreadsheets0.google.com/ccc?key=tFVsxkWVn4fMWYBxxGYokwQ&authkey=CNDvuOcG&authkey=CNDvuOcG#gid=0

Интересно, есть ли в этом случае лучшая функция, чем ROW_NUMBER (), и я чувствую, что делаю слишком много подвыборов, но не знаю, как ее оптимизировать.

Буду очень признателен за любую помощь.

Если что-то не понятно, просто дайте мне знать.

Спасибо.

EDIT:

Причина, по которой я создал auxtable 2, заключается в том, что когда я использую (ROW_NUMBER () OVER (ORDER BY flg) и использую другие команды агрегирования, такие как avg (amt_won) и count (*), которые необходимы, я получаю ошибка, указывающая, что flg должен быть в агрегатной функции, но я не могу упорядочить по агрегатной функции flg.

1 Ответ

2 голосов
/ 08 января 2011

Я сгенерировал некоторые данные для тестирования следующим образом:

create table temporary_six_max as
select id_player, flg_vpip,
       random()*100 * (case flg_vpip when 0 then 1 else -1 end) as amt_won
from (select (random()*1000)::int as id_player, random()::int as flg_vpip
      from generate_series(1,1000000)) source;
create index on temporary_six_max(id_player);

Ваш запрос успешно выполняется на этом, но не совсем генерирует тот же план, я получаю вложенный цикл в нижней части руки, а неСлияние и последующее сканирование в init-плане - вы не выключили enable_seqscan Надеюсь?

Решение, использующее только одно сканирование таблицы:

select row, min(flg) || ' to ' || max(flg) as xyz, avg(amt_won), count(*)
from (select flg, amt_won, ntile(100) over(order by flg) as row
      from (select id_player as pid, amt_won,
                   avg(flg_vpip::int) over (partition by id_player) as flg
            from temporary_six_max
           ) player_stats
     ) chunks
group by 1
order by 1

Плохая новость заключается в том, что на моем компьютере это на самом деле работает хуже , особенно если я достаточно увеличу work_mem, чтобы избежать первой сортировки диска (создание player_stats, сортировка по flg).Несмотря на то, что увеличение work_mem сократило время запроса вдвое, так что я думаю, что это хотя бы начало?

Сказав это, мои запросы выполняются в течение примерно 5 секунд, чтобы обработать входные строки 10E6 во временном_сим_макс.Величина быстрее, чем вы разместили.Ваша таблица вписывается в ваш буферный кеш?Если нет, то решение для одного сканирования может быть гораздо лучше для вас.(Какую версию Postgresql вы используете? "Объяснять (анализировать, буферизовать) выбирать ..." покажет вам количество попаданий / промахов в буфере в 9.0 или просто посмотреть на настройку "shared_buffers" и сравнить с размером таблицы)

...