Как написать эффективный запрос MySQL для удаления определенных строк в зависимости от ограничений - PullRequest
0 голосов
/ 22 января 2010

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

Моя проблема заключается в следующем,

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

Теперь мне нужно найти эффективный способ удаления игр (возраст которых более 18 месяцев) для обычных не премиум-пользователей и сохранить игры для премиум-пользователей.

Упрощение вещей Я получил две таблицы (на самом деле есть еще одна таблица, в которой хранятся участники игры для каждой игры):

Игры

 id=INT
 play_date=DATETIME
 end_score=INT
 player_id_1=INT
 player_id_2=INT

Пользователи

 id=INT
 premium=BOOLEAN (true=enabled, false=not enabled)

Таблица пользователей содержит более 300 000 строк, а таблица игр содержит несколько миллионов строк. Каждый день около 20.000 игр добавляются в таблицу игр.

Какой самый эффективный способ удалить игры старше 18 месяцев у пользователей без премиум-статуса.

До сих пор мы удаляли игры старше 18 месяцев для ВСЕХ пользователей каждое утро понедельника.

Теперь мне нужно учитывать премиальную стоимость и дату игры.

Несколько решений (?):

  • ПРИСОЕДИНЕНИЕ к таблицам, хотя мы говорим о миллионах строк в таблице игр, это было бы нет-нет?
  • Получить каждую запись в игре старше 18 месяцев, затем получить запись для каждого пользователя из player_id_1 & player_id_2, и если ЛЮБОЙ из них Премиум, пусть будет игра, иначе удалите ее, если она старше 18 месяцев. Так, на одну неделю это может быть 20 000 * 7 = 140 000 игр.
  • Над решением, кроме того, что я делаю это каждый час. Затем я должен получить и проверить около 1000 игр.
  • ?? добавить какую-нибудь вспомогательную переменную в таблицу игр? Но что, если пользователь перестанет использовать премиум ....

Любые советы приветствуются ...

Ответы [ 4 ]

3 голосов
/ 22 января 2010

Используйте дату истечения срока и индекс выше этого.

Разрешить NULL в этом столбце.

Премиум-пользователи будут иметь значение NULL в своих играх.

При удалении игр с expire_date

EDIT

Или ведите отдельную таблицу PK реестра с expire_date. Таким образом, записи премиум-пользователей не будут занимать место. Затем вы делаете удаление из xxx, где находится pk (выберите pk из таблицы expiring_table).

Но это не очень хорошее улучшение по сравнению с предыдущим решением.

Возраст

Возможно, вы можете использовать возраст (например, 1 возраст = 1 месяц). И установите поле "month_to_live" в таблице. Каждый месяц вы обновляете поле + = 1 для всех записей, которые не равны нулю. Это использует фильтр равенства. Но, как я уже говорил, я не специалист, поэтому не знаю, какую оптимизацию вы можете извлечь из этого).

Я должен настаивать на поле expire_date (и у вас есть дополнительная возможность продлить период жизни кому угодно, индивидуально, без дополнительных затрат при удалении записей).

1 голос
/ 22 января 2010

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

Кроме того, это обычный ответ на эти вопросы sql query: Запустите «объяснение» для ваших запросов и убедитесь, что у вас правильные индексы.

0 голосов
/ 07 июня 2011

Вам следует избегать решений, которые ОБНОВЛЯЮТ игровую таблицу каждый раз, когда пользователь меняет статус, поскольку это излишне и медленно.

Вот один. Предположим, вы выполняете запрос каждый день в один и тот же час:

DELETE games FROM games
JOIN users u1 ON (u1.id=games.player1_id AND NOT u1.premium)
JOIN users u2 ON (u1.id=games.player2_id AND NOT u2.premium)
WHERE games.play_date BETWEEN DATE_SUB( now(), INTERVAL 18 MONTH 1 DAY 1 HOUR)
AND DATE_SUB( now(), INTERVAL 18 MONTH )

Конечно, у вас должен быть индекс по играм (play_date).

Идея заключается в том, что проверка диапазона дат проверяет только те игры, которые потенциально нуждаются в удалении и еще не были проверены вчерашним запросом. Вид «катящегося окна».

Наоборот, это:

WHERE games.play_date < DATE_SUB( now(), INTERVAL 18 MONTH )

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

0 голосов
/ 22 января 2010

Присоединение не должно быть слишком плохим, я полагаю, вы не выполняете этот запрос "вживую"? Другой вариант - сделать запрос при отображении игр: если пользователь премиум-класса, не ограничивайте, в противном случае ограничьте диапазон.

...