Нужны некоторые предложения для проектирования схемы базы данных - PullRequest
0 голосов
/ 08 апреля 2009

Я разрабатываю очень простую (с точки зрения функциональности), но сложную (с точки зрения масштабируемости) систему, в которой пользователи могут отправлять сообщения друг другу. Думайте об этом как об очень простом чате. Пользователь может вставить сообщение через страницу php. Сообщение короткое и имеет имя получателя.

На другой странице php пользователь может просмотреть все сообщения, которые были ему отправлены, и затем удалить их в базе данных. Вот и все. Это все функциональные возможности, необходимые для этой системы. Как я должен идти о разработке этого (с точки зрения базы данных / PHP)?

Пока у меня есть такая таблица:

  • field1 -> message (varchar)
  • field2 -> получатель (varchar)

Теперь для sql insert я обнаружил, что время, которое требуется, постоянно, независимо от количества строк в базе данных. Так что мой send.php будет иметь гарантированное время возврата, что хорошо.

Но для удаления сообщений мой pull.php займет больше времени, так как количество строк увеличивается! Я считаю, что sql select (и delete) будет занимать больше времени по мере роста строк, и это верно даже после того, как я добавил индекс для поля получателя.

Теперь, если бы это было просто так, что пользователям пришлось бы ждать дольше, прежде чем их сообщения были извлечены на php, тогда все было бы в порядке. Но меня беспокоит то, что когда каждое время службы pull.php занимает очень много времени, сервер php начинает отказывать в соединениях с каким-либо запросом. Или хуже, сервер может просто умереть.

Итак, вопрос в том, как спроектировать это так, чтобы оно масштабировалось? Любые советы / подсказки?

PS. Некоторые оценки по номерам:

  • количество пользователей начинается с 50 000 и увеличивается.
  • каждый пользователь в среднем хранит около 10 сообщений, прежде чем другой конец может его сбросить.
  • каждый пользователь отправляет около 10-20 сообщений в день.

ОБНОВЛЕНИЕ от чтения ответов до сих пор:

Я просто хочу уточнить, что удаление меньшего количества сообщений из файла pull.php не помогает. Даже просто потянуть одно сообщение займет много времени, когда таблица огромна. Это связано с тем, что в таблице есть все сообщения, поэтому вы должны сделать такой выбор:

select message from DB where recipient = 'John'

даже если вы измените его на это, это не сильно поможет

select top 1 message from DB where recipient = 'John'

Пока что из ответов кажется, что чем длиннее таблица, тем медленнее будет выбор O (n) или чуть лучше, никак не обойти его. Если это так, как я должен справиться с этим со стороны PHP? Я не хочу, чтобы страница php проваливалась на http, потому что пользователь будет сбит с толку и в итоге обновится, как сумасшедший, что делает его еще хуже.

Ответы [ 8 ]

3 голосов
/ 08 апреля 2009
  1. Следуйте правилам нормализации. Попробуйте достичь 3-й нормальной формы. Идти дальше для такого типа приложений, вероятно, не стоит. Держите свои столы тонкими.
  2. На самом деле не удаляйте строки, просто пометьте их как удаленные с помощью битового флага. Если вам действительно нужно удалить их для какого-либо типа обслуживания / очистки, чтобы уменьшить размер. Отметьте их как удаленные, а затем создайте процесс очистки для архивирования или удаления записей в часы низкого использования.
  3. Целочисленные значения проще для SQL-сервера, чем символьные значения. Таким образом, вместо того, чтобы в качестве получателя = 'Джон' использовать WHERE Recipient_ID = 23, вы получите такой тип поведения, когда нормализуете свою базу данных.
3 голосов
/ 08 апреля 2009

Не используйте VARCHAR для получателя. Лучше всего сделать таблицу получателей с первичным ключом , который является целым числом (или bigint, если вы ожидаете очень большое количество людей).

Тогда, когда вы сделаете ваши избранные заявления:

SELECT message FROM DB WHERE recipient = 52;

Скорость извлечения строк будет намного быстрее.

Кроме того, я считаю, что индексы MySQL B-Trees , что в большинстве случаев равно O (log n).

3 голосов
/ 08 апреля 2009

дизайн базы данных для этого прост, как вы предлагаете. Поскольку это занимает больше времени, когда пользователь получает больше сообщений, вы можете просто разбить результаты на страницы. Показать первое 10/50/100 или что-то еще имеет смысл и только тянуть те записи. Вообще говоря, ваше время не должно сильно увеличиваться, если объем сообщений не увеличивается на порядок или более. Вы должны быть в состоянии получить 1000 коротких сообщений менее чем за секунду. Теперь может потребоваться больше времени для отображения страницы в этот момент, но именно здесь должна помочь нумерация страниц.

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

2 голосов
/ 09 апреля 2009

Таблица базы данных без индекса называется кучей, запрос к куче приводит к тому, что каждая строка таблицы оценивается даже с предложением where, а big-o для кучи - O (n), где n количество строк в таблице. Добавление индекса (а это действительно зависит от базовых аспектов вашего механизма базы данных) приводит к сложности O (log (n)), чтобы найти соответствующую строку в таблице. Это потому, что индекс, безусловно, реализован в виде b-дерева. Добавление строк в таблицу даже при наличии индекса является операцией O (1).

 > But for pulling down messages, my pull.php will take longer as the number of rows 
 increase! I find the sql select (and delete) will take longer as the rows grow and
 this is true even after I have added an index for the recipient field.

Если вы не вставляете в середину индекса, в этот момент ядру базы данных потребуется сдвинуть строки вниз, чтобы приспособиться. То же самое происходит при удалении из индекса. Помните, что существует более одного вида индекса. Убедитесь, что используемый вами индекс не является кластеризованным, так как больше данных необходимо просеивать и перемещать с помощью вставок и удалений.

FlySwat предоставил вам лучший вариант ... не используйте СУБД, потому что ваши сообщения не являются реляционными в формальном смысле. Вы получите намного лучшую производительность от файловой системы.

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

Я предлагаю не реализовывать такого рода функциональные возможности в вашей СУБД, если вы помните, что выбираете, обновляете, вставляете, удаляете все блокировки мест на страницах вашей таблицы. Если вы продолжите добавлять эту функциональность в базу данных, тогда запустите ваши выборки с подсказкой блокировки nolock, если она доступна на вашей платформе для повышения параллелизма. Кроме того, если у вас так много одновременно работающих пользователей, разделите ваши таблицы по вертикали, как предложил dbarker, и поместите эти файлы базы данных на отдельные диски (не только тома, но и отдельное оборудование), чтобы увеличить параллелизм ввода-вывода.

1 голос
/ 08 апреля 2009

Итак, вопрос в том, как спроектировать это так, чтобы оно масштабировалось? Любые советы / подсказки?

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

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

http://wiki.secondlife.com/wiki/Message_Queue_Evaluation_Notes

0 голосов
/ 08 апреля 2009

Это неизбежная проблема - больше сообщений, больше времени для поиска запрошенных. Единственное, что вы можете сделать, это то, что вы уже сделали - добавить индекс и повернуть время поиска O (n) для полного сканирования таблицы в O (log (u) + m) для поиска кластерного индекса, где n - число от общего количества сообщений, u количество пользователей и m количество сообщений на пользователя.

0 голосов
/ 08 апреля 2009

Ограничьте количество строк, которые ваш pull.php будет отображать одновременно.

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

Вы должны ограничить свои данные в SQL, вернуть самые последние N строк.

EDIT Поместите индекс на Получателя, и это ускорит его. Вам понадобится другой столбец, чтобы различать строки, если вы хотите взять верхние 50 или что-то, возможно SendDate или поле с автоинкрементом Кластерный индекс будет замедлять вставки, поэтому используйте обычный индекс там.

0 голосов
/ 08 апреля 2009

Вы можете всегда иметь только одну строку для каждого пользователя и просто объединять сообщения в одну длинную запись. Если вы храните сообщения в течение длительного периода времени, это не лучший способ, но он сводит вашу проблему к одному обнаружению и объединению во время хранения и одному обнаружению во время получения. Трудно сказать без подробностей - часть того, что усложняет проектирование БД, - это компромиссное решение всех задач системы. Без всех деталей трудно дать совет о лучшем компромиссе.

РЕДАКТИРОВАТЬ: Я думал, что я был достаточно ясно об этом, но, очевидно, нет: вы не будете делать это, если вы не закрываете очередь читателя, когда он читает. Вот почему я попросил разъяснений.

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