Я ищу лучший способ хранить набор «постов», а также комментарии к этим постам в SQL. Представьте себе дизайн, похожий на «Стену» на Facebook, где пользователи могут писать посты на своей стене, а другие пользователи могут комментировать эти посты. Мне нужно иметь возможность отображать все сообщения на стене, а также комментарии.
Когда я только начинал, у меня была такая таблица:
CREATE Table wallposts
(
id uuid NOT NULL,
posted timestamp NOT NULL,
userid uuid NOT NULL,
posterid uuid NOT NULL,
parentid uuid NOT NULL,
comment text NOT NULL
)
идентификатор уникален, parentid будет нулевым в исходных сообщениях и будет указывать на идентификатор, если строка является комментарием к существующему сообщению. Достаточно просто и очень быстро, чтобы вставить новые данные. Тем не менее, делая выбор, который вернул бы меня:
POST 1
COMMENT 1
COMMENT 2
POST 2
COMMENT 1
COMMENT 2
Независимо от того, в каком порядке строки существовали в базе данных, оказалось чрезвычайно сложно. Я, очевидно, не могу просто заказать по дате, так как кто-то может прокомментировать пост 1 после того, как пост 2 был опубликован. Если я сделаю LEFT JOIN, чтобы получить родительский пост во всех строках, а затем отсортировать сначала по этой дате, все исходные посты сгруппируются, так как они будут иметь значение null.
Тогда я получил эту идею:
CREATE TABLE wallposts
(
id uuid NOT NULL,
threadposted timestamp,
posted timestamp,
...
comment text
)
На оригинальном посте нить размещена и размещена будет одинаково. Для комментария отметка времени будет временем, когда исходное сообщение было опубликовано, а "отправлено" - временем публикации комментария в этой теме. Теперь я могу просто сделать:
select * from wallposts order by threadposted, posted;
Это прекрасно работает, однако меня раздражает одна вещь. Если два человека создают сообщение одновременно, комментарии к двум сообщениям будут объединены, поскольку они будут иметь одинаковую метку времени. Я мог бы использовать «галочки» вместо datetime, но все равно точность составляет всего 1/1000 секунды. Я также мог бы установить уникальное ограничение для размещения и публикации в потоке, что делает вставки немного дороже, но если бы у меня было несколько серверов баз данных в ферме, вероятность коллизии все еще была. В любом случае, я чуть было не пошел вперед, так как шансы на это чрезвычайно малы, но я хотел посмотреть, смогу ли я съесть свой пирог и при этом иметь его тоже. Главным образом для моего собственного образовательного любопытства.
Третье решение - хранить эти данные в форме графика. Каждый узел будет иметь указатель v-left и v-right. Я мог бы заказать "слева", который будет проходить по дереву в нужном мне порядке. Однако каждый раз, когда кто-то вставляет комментарий, мне приходится заново балансировать все дерево. Это создало бы кучу блокировок строк и всевозможных проблем, если бы сайт был очень занят. Кроме того, это своего рода крайность, которая также вызывает проблемы с репликацией. Поэтому я быстро бросил эту идею.
Я также думал о том, чтобы просто сохранить исходные сообщения и затем сериализовать комментарии в двоичном виде, поскольку кому нужны отдельные комментарии. Это было бы очень быстро, однако, если пользователь хочет удалить свой комментарий или добавить новый комментарий в конец, я должен десериализовать эти данные, изменить структуру, затем сериализовать их обратно и обновить строку. Если несколько человек одновременно комментируют одно и то же сообщение, у меня могут возникнуть случайные проблемы с этим.
Итак, вот что я в конце концов сделал. Я запрашиваю все сообщения, упорядоченные по введенной дате. На промежуточном уровне программного обеспечения я перебираю набор записей и создаю «стопку» исходных сообщений, каждый узел в стеке указывает на связанный список комментариев. Когда я сталкиваюсь с оригинальным сообщением, я помещаю новый узел в стек, и когда я сталкиваюсь с комментарием, я добавляю узел в связанный список. Я организовал это в памяти, чтобы я мог пройти набор записей один раз и получить O (n). После создания представления стены в памяти я снова просматриваю эту структуру данных и выписываю HTML. Это прекрасно работает и имеет супер-быстрые вставки и супер-быстрое выделение, и никаких странных проблем с блокировкой строк; однако это немного тяжелее на моем уровне представления и требует, чтобы я построил в памяти представление стены пользователя, чтобы перемещать вещи так, чтобы это было в правильном порядке. Тем не менее, я считаю, что это лучший подход, который я нашел до сих пор.
Я подумал, что я бы посоветовался с другими экспертами по SQL, чтобы выяснить, есть ли лучший способ сделать это, используя какие-то странные СОЕДИНЕНИЯ или СОЮЗЫ или что-то, что все равно будет работать с миллионами пользователей.