Эффективное хранение набора внешних ключей (Serialize vs New Table) - PullRequest
1 голос
/ 18 января 2012

Мне нужно сохранить список user_id с, которые просмотрели часть контента, чтобы вычислить уникальные пользовательские просмотры. user_id - это поле INT(10).

Я мог бы создать таблицу с user_id, content_id и viewed и добавлять строки каждый раз, когда пользователь просматривает контент, но это кажется медленным. Для каждого фрагмента контента, который просматривает пользователь, мне придется запросить что-то вроде

SELECT COUNT(*) FROM viewed_table WHERE content_id = $content_id;

, чтобы получить количество просмотров, а затем

SELECT COUNT(*) FROM viewed_table WHERE user_id = $user_id AND content_id = $content_id;

, чтобы увидеть, просматривал ли пользователь этот контент, а затем вставить строку, если нет. (2 или 3 дополнительных запроса каждый раз, когда пользователь смотрит на что-то).

ИЛИ ...

Должен ли я добавить поле viewed в мою таблицу содержимого и unserialize() / serialize() массив каждый раз, когда добавляю user_id? json_encode() - еще одна похожая опция, которая кажется более быстрой для больших наборов данных.

Какой вариант является самым быстрым / масштабируемым для растущего сайта? Спасибо за вашу помощь!

Ответы [ 3 ]

2 голосов
/ 18 января 2012

Практическое правило: сериализация реляционных данных в целом, внешних ключей в частности == шоссе в ад.

Есть таблица, в которой вы храните суммы всех представлений, и вы только увеличиваете / уменьшаете их.Это должно быть быстрее, чем SELECT COUNT(*) FROM viewed_table WHERE content_id = $content_id;

Чтобы узнать, просматривал ли данный пользователь данную страницу SELECT 1 FROM viewed_table WHERE user_id = $user_id AND content_id = $content_id LIMIT 1;.Это вернет 0 или 1 строку, так что вам нужно только проверить это.

1 голос
/ 18 января 2012

Вы можете сделать это:

viewed_table
----------------------------
user_id int(10)
content_id int(10)
primary key (user_id, content_id)

Для вставки записи:

INSERT IGNORE INTO viewed_table (user_id, content_id) VALUES ($user_id, $content_id)

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

Если вы хотите реализовать таблицу итогов, это также точка, в которой вы добавите один к итогу для выбранного content_id.

viewed_table_totals
----------------------------
content_id int(10)
view_count int(10)
primary key (content_id)

Обновление строки:

INSERT INTO viewed_table_totals (content_id, view_count) VALUES($content_id, 1)
  ON DUPLICATE KEY UPDATE view_count = view_count + 1

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

0 голосов
/ 18 января 2012

Без сомнения, первый вариант.

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

Вы могли бы улучшить это, сохранив счетчик в памяти (с чем-то вроде Memcached или Redis), или добавив столбец view_count в таблицу содержимого и просто увеличивая это число всякий раз, когда вы добавляете в visible_table.

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