Как превысить 64 канала (биты) в этой издательской системе

РЕДАКТИРОВАТЬ:

В приведенном ниже вопросе я упростил свою проблему, чтобы ее было легко объяснить. Теперь я вижу, основываясь на первых нескольких комментариях, что я упростил это. Поэтому, когда вы читаете, помните об этом новом факте: в системе может быть почти столько же издателей, сколько пользователей, и у каждого издателя может быть свой собственный список (предпочтительно тысячи) групп интересов. Короче говоря, примите это как данность, что скорость важна, и что простые списки просто не будут сокращать это …

КОНЕЦ РЕДАКТИРОВАНИЯ.

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

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

Например, группы интересов могут быть следующими:

  • бит 0 (десятичный 1): рыбалка
  • бит 1 (десятичный 2): ходьба куста
  • бит 2 (десятичный 4): Sky Diving

В этом случае маской публикации может быть, скажем, «3» («Рыбалка и прогулка по Бушу»). Пользователь с маской чтения «5» («Рыбалка и дайвинг в небе») будет иметь доступ к статье, а пользователь с маской чтения «4» — нет. Выбор сообщений происходит в рамках SQL-запроса. Запрос просто использует предложение WHERE, которое возвращает логический результат побитового И между маской чтения пользователя и маской публикации каждого поста.

Итак … это работает очень хорошо, за исключением очевидной проблемы: я ограничен 64 группами интересов. Что касается жизни, я не могу придумать элегантного способа обойти это.

Я мог бы добавить вторую пару масок и основать предложение WHERE на ((PubMask1 AND ReadMask1) || (PubMask2 AND ReadMask2)) однако этот «линейный» подход дает мне только 128 групп. Что если я хочу, скажем, 3000?

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

Есть ли другие возможности, которые я упускаю? Например, есть ли способ хранить длинную и длинную строку нулей и единиц и выполнять над ними двоичную арифметику?

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

0

Решение

То, что вы предлагаете здесь, это спускаться по глубокой, глубокой кроличьей норе и фактически не приведет к каким-либо улучшениям производительности. Фактически, это, вероятно, будет иметь противоположный эффект, делая вашу схему не просто неудобной в использовании, но ограниченной из-за проблем с производительностью из-за вашего нестандартного подхода к пометке. Чем больше вы идете против структуры в СУБД, такой как MySQL, тем больше вы наказываете проблемами с производительностью.

Индивидуальный подход к этому состоит в том, чтобы иметь простой таблица ассоциации который связывает посты с группами:

CREATE TABLE post_group_links(
id INT AUTO_INCREMENT PRIMARY KEY,
post_id INT NOT NULL,
group_id INT NOT NULL,
UNIQUE KEY `index_pgl_post_group` (`post_id`,`group_id`)
);

Тот UNIQUE Ограничение индекса означает, что вы можете иметь одну и только одну связь между постом и группой. База данных, такая как MySQL, позволяет легко и быстро получить все статьи для группы:

SELECT posts.* FROM posts
LEFT JOIN post_group_links ON posts.id=post_id
WHERE post_group_links.group_id=?

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

Если вы хотите найти сообщения в более чем одной группе, используя эксклюзивные AND это также возможно, хотя и медленнее, с чем-то вроде следующего:

SELECT posts.* FROM posts
LEFT JOIN post_group_links ON posts.id=post_id
WHERE post_group_links.group_id IN (?,?,?)
GROUP BY posts.id
HAVING COUNT(post_group_links.id)=3

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

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

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

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]