Как оптимизировать эту таблицу MySQL? - PullRequest
6 голосов
/ 05 июня 2010

Это для предстоящего проекта. У меня есть две таблицы: первая отслеживает фотографии, а вторая отслеживает рейтинг фотографий

Photos:
+-------+-----------+------------------+ 
| id    | photo     | current_rank     |
+-------+-----------+------------------+ 
| 1     | apple     | 5                |
| 2     | orange    | 9                |
+-------+-----------+------------------+

Ранг фотографий постоянно меняется, и вот таблица, которая отслеживает это:

Ranks:
+-------+-----------+----------+-------------+ 
| id    | photo_id  | ranks    | timestamp   |
+-------+-----------+----------+-------------+
| 1     | 1         | 8        | *           |
| 2     | 2         | 2        | *           |
| 3     | 1         | 3        | *           |
| 4     | 1         | 7        | *           |
| 5     | 1         | 5        | *           |
| 6     | 2         | 9        | *           |
+-------+-----------+----------+-------------+ * = current timestamp

Каждый ранг отслеживается для целей отчетности / анализа. [Изменить] Пользователи будут иметь доступ к статистике по запросу.

Я разговаривал с кем-то, кто имеет опыт в этой области, и он сказал мне, что хранение рангов, как указано выше, - это путь. Но я не уверен еще.

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

Я думал об этом:

Ranks:
+-------+-----------+--------------------+
| id    | photo_id  | ranks              |
+-------+-----------+--------------------+
| 1     | 1         | 8:*,3:*,7:*,5:*    |
| 2     | 2         | 2:*,9:*            |
+-------+-----------+--------------------+ * = current timestamp

Это означает некоторый дополнительный код в PHP для разделения ранга / времени (и сортировки), но для меня это нормально.

Это правильный способ оптимизации таблицы для повышения производительности? Что бы вы порекомендовали?

Ответы [ 9 ]

7 голосов
/ 05 июня 2010

Первый. Период.

На самом деле вы потеряете намного больше. Временная метка, хранящаяся в столбце int, будет занимать всего 4 байта.

В то время как та же временная метка, сохраненная в строковом формате, займет 10 байтов.

2 голосов
/ 05 июня 2010

Ваш первый дизайн подходит для реляционной базы данных. Избыточность в ключевых столбцах предпочтительнее, потому что она дает вам гораздо больше гибкости в том, как вы проверяете и запрашиваете рейтинги. Вы можете выполнять сортировку, подсчет, усреднение и т. Д. В SQL без необходимости писать какой-либо код PHP, чтобы разбить строку шестью способами с воскресенья.

Похоже, вы хотели бы использовать базу данных, отличную от SQL, например, CouchDB или MongoDB. Эти будут позволять вам хранить полуструктурированный список рейтингов прямо в записи для фотографии, а затем эффективно запрашивать рейтинги. С оговоркой, что вы на самом деле не знаете, что рейтинги имеют правильный формат, как вы делаете с SQL.

2 голосов
/ 05 июня 2010

Я бы придерживался вашего первого подхода. Во втором у вас будет много данных, хранящихся в строке, так как время идет, оно получает больше рангов! То есть, если фотография получает тысячи и тысячи рейтинга.

Первый подход также более удобен в обслуживании, то есть если вы хотите удалить ранг.

1 голос
/ 06 июня 2010

Из двух вариантов - как все говорили до меня - это должен быть вариант 1.

Что вас действительно должно беспокоить, так это узкие места в самом приложении. Будут ли пользователи часто обращаться к историческим данным, или они будут отображаться только для нескольких избранных пользователей? Если ответ таков, что каждый может увидеть исторические данные о рангах, то вариант 1 достаточно хорош. Если вы не собираетесь ссылаться на исторические ранги так часто, то вы можете создать третью «архивную» таблицу, и перед обновлением рангов вы можете скопировать строки исходной таблицы рангов в архивную таблицу. Это обеспечивает минимальное количество строк в основной вызываемой таблице.

Помните, что если вы обновляете строки, а их десятки тысяч, может оказаться более полезным получить результаты в вашем коде (PHP / Python / и т. Д.), Усечь таблицу и вставить результаты, а не обновить это строка за строкой, так как это было бы потенциальным узким местом.

Возможно, вы также захотите посмотреть шардинг (горизонтальное разбиение) - http://en.wikipedia.org/wiki/Shard_%28database_architecture%29

И никогда не забывайте хорошо индексировать.

Надеюсь, это помогло.

1 голос
/ 05 июня 2010

Нормализованные данные или ненормализованные данные. Вы найдете тысячи статей об этом. :)

Это действительно зависит от ваших потребностей.

Если вы хотите построить свою базу данных только с учетом производительности (скорости или потребления ОЗУ или ...), вам следует доверять только цифрам. Для этого вам нужно профилировать ваши запросы с ожидаемым объемом данных (вы можете сгенерировать данные с помощью сценария, который вы пишете). Чтобы профилировать свои запросы, узнайте, как прочитать результаты 2 следующих запросов:

  • EXPLAIN extended...
  • SHOW STATUS

Затем узнайте, что нужно сделать, чтобы улучшить показатели (настройки MySQL, структура данных, оборудование и т. Д.).

Для начала я действительно советую эти 2 замечательные статьи:

  1. http://www.xaprb.com/blog/2006/10/12/how-to-profile-a-query-in-mysql/
  2. http://ajohnstone.com/archives/mysql-php-performance-optimization-tips/

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

1 голос
/ 05 июня 2010

Я думаю, что «попадание» в базу данных из-за чрезмерной нормализации (многократного запроса к таблице рангов) прекрасно предотвращается путем «кэширования» последнего ранга в current_rank. На самом деле не имеет значения, как сильно растут ранги, если к ним редко обращаются (вы сказали аналитику / отчетность), никогда не обновляете, а просто вставляете записи в конце: даже в очень легком окне не возникнет проблем с миллионами строк в этой таблице.

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

Конечно, если вам нужны все старые данные, и всегда по photo_id, вы можете запланировать запуск по расписанию в другой таблице Rankings_old, возможно с photo_id, годом, месяцем, рейтингами (включая временные метки), когда месяц закончится, поэтому поиск старых данных по-прежнему легко возможен, но обновлять рейтинги и ранжирование не требуется, только вставка в конце таблицы.

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

0 голосов
/ 06 июня 2010

Ваш второй дизайн очень опасен, если у вас есть 1 миллион голосов за фотографию. Может ли PHP справиться с этим?

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

0 голосов
/ 06 июня 2010

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

0 голосов
/ 05 июня 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...