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

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

1 голос
/ 07 декабря 2010

Я проверил следующий запрос в 2 базах данных с точно такой же структурой, в первом, с 4М записями, он вернул мне результат за 33 секунды. Вторая таблица содержит 29 миллионов строк, и с момента выполнения запроса прошло 16 часов, а я еще не получил ответ.

SELECT sbvpip*4 as smallbvpip,btnvpip*4 as buttonvpip, sum(amt_won)*400/count(*) AS winrate, count(*) as count

FROM holdem_hand_player_statistics

    JOIN (

    SELECT id_player AS pid2, id_hand AS hid, sbvpip
    FROM holdem_hand_player_statistics

        JOIN (
        SELECT id_player AS pid, ROUND(avg(flg_vpip::int)*25) AS sbvpip
        FROM holdem_hand_player_statistics
        WHERE position = 8 AND cnt_players = 6
        GROUP BY id_player
        ) AS auxtable
        ON pid = id_player

    WHERE position = 8 AND cnt_players = 6
    ) AS auxtable2
    ON hid = id_hand


    JOIN (

    SELECT id_player AS pid4, id_hand AS hid2, btnvpip
    FROM holdem_hand_player_statistics

        JOIN (
        SELECT id_player AS pid3, ROUND(avg(flg_vpip::int)*25) AS btnvpip
        FROM holdem_hand_player_statistics
        WHERE position = 0 AND cnt_players = 6
        GROUP BY id_player
        ) AS auxtable3
        ON pid3 = id_player

    WHERE position = 0 AND cnt_players = 6
    ) AS auxtable4
    ON hid2 = id_hand


WHERE POSITION = 0 and cnt_players = 6



GROUP BY sbvpip,btnvpip
ORDER BY 1,2;

Что я могу сделать, чтобы этот запрос выполнялся быстрее?

Возможно ли, что таблица повреждена или что-то в этом роде? Одна таблица только в 7 ~ 8 раз больше другой, но обработка занимает в 15000 раз больше времени, это нормально?

Любые другие комментарии приветствуются!

Если мой английский не ясен, просто дайте мне знать, что я постараюсь выразить себя по-другому.

Большое спасибо за любую помощь,

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ:

Из переменных, которые я использую, 3 из них являются индексами: id_hand, id_player, position. Первичный ключ (id_hand, id_player). В таблице 129 столбцов и 6 индексов.

Я также запустил EXPLAIN в обеих таблицах и получил разные результаты. Оба результаты находятся в электронной таблице gdocs: https://spreadsheets.google.com/ccc?key=tGxqxVNzHYznb1VVjtKyAuw&authkey=CJ-BiYkN&authkey=CJ-BiYkN#gid=0

Ответы [ 4 ]

3 голосов
/ 07 декабря 2010

Я бы предположил, что на одном из серверов индексирование является либо несуществующим, либо неправильным.

Также может быть блокировка, препятствующая завершению запроса.Особенно, если там есть незафиксированная сделка.

2 голосов
/ 07 декабря 2010

Возможно, вы используете намного больше памяти для сортировки большего числа строк: какова ваша настройка work_mem? Точно так же и с буферной кэш-памятью - поскольку вы сканируете одну и ту же таблицу несколько раз, подгонка строк в кеш, вероятно, будет иметь решающее значение.

Кроме того, вам следует пересмотреть этот запрос и попытаться найти способы, позволяющие не присоединять таблицу статистики обратно к себе так много раз. Трудно советовать без каких-либо небольших тестовых данных и ожидаемого результата. Какую версию PostgreSQL вы используете? С 8.4 вы можете получить как auxtable, так и auxtable3 из одного CTE как минимум ...

1 голос
/ 08 декабря 2010

Я мог легко поверить, что запросы занимают так много времени. У вас есть таблица строк 29M, в которой вы работаете с несколькими группами и несколько раз связываетесь с собой в разных столбцах. Если вся таблица не помещается в память, может быть много страниц, которые не нужны с 1/7 строк. Работая внутрь, вы:

  1. Выбор из таблицы строк 29M на позиции = 0 и cnt_players = 6
  2. Двойная ссылка на таблицу строк 29M в столбце id_hand
  3. Фильтрация таблицы строк 29M дважды для cnt_players = 6 и позиций 0 и 8 и вычисление среднего значения flg_vpip по игроку
  4. Ссылка на сгруппированные результаты в id_hand для миллионов строк

Не могли бы вы разделить стол на отдельные? Что именно означают ваши поля и как будет выглядеть образец руки?

Вам нужны индексы как минимум для id_player, id_hand, position и cnt_players.

Возможно, было бы хорошо включить все поля в индекс. Я не уверен насчет postgresql, но SQL Server может пропустить загрузку реальных страниц данных таблицы, если все данные, необходимые для запроса, находятся в индексе. Поэтому, если бы у вас был индекс позиции, cnt_players, id_player и flg_vpip, ваши самые внутренние выборки, вероятно, были бы намного быстрее.

Я думаю, что лучшим способом было бы заранее рассчитать эти внутренние выборки в одну или две таблицы, если вы не собираетесь часто выполнять запрос.

select id_player, position, cnt_players,
    ROUND(avg(flg_vpip::int)*25) AS avg_vpip
into auxtable
from holdem oldem
group by id_player, position, cnt_players

alter table auxtable add constraint PK_auxtable 
    primary key clustered (id_player, position, cnt_players)

Как это:

SELECT sbvpip*4 as smallbvpip,btnvpip*4 as buttonvpip, sum(amt_won)*400/count(*) AS winrate, count(*) as count
FROM holdem
    JOIN (
        SELECT id_player AS pid2, id_hand AS hid, sbvpip
        FROM holdem
            JOIN auxtable ON auxtable.id_payer = holdem.id_player 
                and auxtable.position = holdem.position
                and auxtable.cnt_players = holdem.cnt_players
        WHERE holdem.position = 8 AND holdem.cnt_players = 6
    ) AS auxtable2 ON hid = id_hand
1 голос
/ 07 декабря 2010

запрос выглядит нормально.чтобы повысить производительность, попробуйте выполнить индексацию, как сказал @HLGEM.Также попробуйте выполнить каждый отдельный подзапрос, чтобы увидеть, какой из них имеет низкую производительность.

...