2012-05-31 2 views
3

Я заранее извиняюсь, если этот вопрос слишком специфичен, но я считаю, что это довольно типичный сценарий: join и group by s увязку с дбом и лучший способ обойти его. Моя конкретная проблема заключается в том, что мне нужно создать табло на основе:Временная таблица заболачивания базы данных - как оптимизировать?

  • пьес (идентификатор пользователя, GameID, оценка) 40M строк
  • игр (GameID) 100K строк
  • app_games (AppID, GameID), то есть, игры сгруппированы в приложениях и есть общий балл за приложение, которое является суммой всех связанных с ним игр < 20 строк

пользователи могут играть в несколько раз, и их лучший результат для каждой игры записывается. Сформулировать запрос легко, я сделал несколько вариантов, но у них есть противная тенденция запираться в «скопировании временной таблицы» в течение 30-60 секунд при загрузке.

Что я могу сделать? Существуют ли переменные сервера, которые я должен настраивать, или есть способ переформулировать запрос, чтобы сделать его быстрее? Производная версия запроса, который я использую выглядит следующим образом (минус таблица пользователей присоединиться, чтобы захватить имя):

select userID,sum(score) as cumscore from 
     (select userID, gameID,max(p.score) as score 
     from play p join app_game ag using (gameID) 
     where ag.appID = 1 and p.score>0 
     group by userID,gameID) app_stats 
    group by userid order by cumscore desc limit 0,20; 

Или как временную таблицу:

drop table if exists app_stats; 
    create temporary table app_stats 
     select userID,gameID,max(p.score) as score 
     from play p join app_game ag using (gameID) 
     where ag.appID = 1 and p.score>0 
     group by userid,gameID; 
    select userID,sum(score) as cumscore from app_stats group by userid 
     order by cumscore desc limit 0,20; 

У меня есть индексы, как следует:

show indexes from play; 
+-------+------------+----------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+ 
| Table | Non_unique | Key_name    | Seq_in_index | Column_name  | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | 
+-------+------------+----------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+ 
| play |   0 | PRIMARY    |   1 | playID   | A   | 38353712 |  NULL | NULL |  | BTREE  |   | 
| play |   0 | uk_play_uniqueID  |   1 | uniqueID   | A   | 38353712 |  NULL | NULL | YES | BTREE  |   | 
| play |   1 | play_score_added  |   1 | dateTimeFinished | A   | 19176856 |  NULL | NULL | YES | BTREE  |   | 
| play |   1 | play_score_added  |   2 | score   | A   | 19176856 |  NULL | NULL |  | BTREE  |   | 
| play |   1 | fk_playData_game  |   1 | gameID   | A   |  76098 |  NULL | NULL |  | BTREE  |   | 
| play |   1 | user_hiscore   |   1 | userID   | A   |  650062 |  NULL | NULL | YES | BTREE  |   | 
| play |   1 | user_hiscore   |   2 | score   | A   |  2397107 |  NULL | NULL |  | BTREE  |   | 
+-------+------------+----------------------+--------------+------------------+-----------+-------------+----------+--------+------+------------+---------+ 

ответ

2

Я подозреваю, что оба запроса при создании таблицы temp в основном должны проходить через все данные в вашей таблице (а также в вашем запросе «делать все подряд»). Если у вас много данных, которые собираются занять некоторое время.

Я бы сохранил отдельный стол с идентификатором и общим счетом для каждого игрока. Всякий раз, когда вы обновляете таблицу воспроизведения, также обновляйте сводную таблицу. Если они не синхронизируются, просто прекратите сводную таблицу и заново создайте данные из таблицы воспроизведения. (Или, если вы уже используете redis в своей инфраструктуре, вы можете сохранить там сводку - у нее есть функции, чтобы сделать эту вещь очень быстрой).

+0

Я согласен с сохранением итогов игрока. –

+0

Какие функции? Мы используем memcached, чтобы я мог кэшировать все это как массив, а затем просто изменять элементы, которые нужно изменить, получая/устанавливая один и тот же элемент. По какой-то причине я не видел такого memcached, как это (хотя я думал об этом) - вроде как наполовину к типу nosql типа db. – mmdanziger

+1

Memcached не так хорош для этого (если вам нужно обновить результаты в режиме реального времени), потому что вы не можете легко получить список результатов. redis имеет «сортированные наборы», которые так хорошо подходят для вашего случая использования, что, если я правильно помню, это практически пример в их документации: http://redis.io/topics/data-types#sorted-sets –

0

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

+0

Раньше я никогда не пользовался видами, сейчас я их посмотрю. – mmdanziger

+0

Почему бы сделать просмотр быстрее? MySQL не имеет материализованного представления. –