Вот в нашем любимом phpBB2 тексты сообщений хранятся в отдельной таблице, я вот подумал а собственно есть ли смысл в этом ? То есть если есть таблица [sql]CREATE TABLE `forum_posts` ( `post_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `topic_id` int(10) unsigned NOT NULL, `user_id` int(10) unsigned NOT NULL, `post_text` text NOT NULL, PRIMARY KEY (`post_id`) ) ENGINE=MyISAM;[/sql] и выборка идёт [sql]SELECT `post_text` FROM `forum_posts_text` WHERE `topic_id` =20 ORDER BY `post_id` ASC LIMIT 20, 10;[/sql] будет ли быстрее работать если сделать 2 таблицы [sql]CREATE TABLE `forum_posts` ( `post_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `topic_id` int(10) unsigned NOT NULL, `user_id` int(10) unsigned NOT NULL, PRIMARY KEY (`post_id`) ) ENGINE=MyISAM;[/sql] [sql]CREATE TABLE `forum_posts_text` ( `post_id` int(10) unsigned NOT NULL, `post_text` text NOT NULL, PRIMARY KEY (`post_id`) ) ENGINE=MyISAM;[/sql] и выбирать сначала поля `post_id` из `forum_posts` а уже вторым запросом выбирать `post_text` из таблицы `forum_posts_text` с помощью [sql]SELECT `post_text` FROM `forum_posts_text` WHERE `post_id` IN (2, 5, 20);[/sql] Знаю что для человека с моим количеством сообщений вопрос кажется глуповат, но я реально не знаю (и хотел бы узнать, на рнр-клубе было подобное обсуждение, но на сколько я помню так там ни к чему и не пришли)
:? одна таблица с индексами для ускорения выборки и один запрос быстрее чем две таблицы. наверное ведь чем больше таблиц тем больше обращений к жёсткому диску, при множестве запросов на выборку получим бутылочное горлышко в виде жёсткого диска. а на самом деле надо померять скорость на реальной задачке. иначе все оценки субъективны.
Vladson Имхо, смысла в этом нет. Просто сделали "на всякий случай" отдельную таблицу :? Я мог бы сказать, что смысл в этом есть, если бы в одной таблице все поля были бы фиксированной ширины (соответственно тип таблицы MyISAM Fixed), а в другой - произвольной (MyISAM Dynamic). В случае крэша данных первую таблицу было бы легче восстановить. Но, насколько я помню, там и в первой таблице тоже есть текстовые поля (имя автора, заголовок сообщения), да и нафиг восстанавливать только одну таблицу когда во второй самые важные данные? В общем это ошибка проектирования имхо, и очень жаль что они ее протащили из phpBB в phpBB2.
Вопрос не столько в phpBB сколько в том стоит ли повторять их ошибку при написании другого форума... Дело в том что при проектировании БД я столкнулся с тем что удобнее делать всё в одной таблице, но вот при большом размере таблицы не будет ли тормозов ? (при условии что выборка идёт только по int полям) PS я не делаю форум (нет финансирования) пока только в мечтах проектирую, хз будет ли когда нибудь время/деньги написать
Dagdamor С радостью выслушаю другие мнения (если они есть) но пока мне кажется что вы абсолютно правы. (я с самого начала подозревал что это так, но слепо быть уверенным в том чего не знаю я не привык)
Вероятно, стоит все таки разделить таблицу постов, таблицу топиков и таблицу структуры. ибо таблица топов обновляется заметно реже таблицы постов, не говоря уже о структуре. соответственно, разделение таблицы постов и топов позволит избежать постоянного "перетряхивания" индекса топов, что при большом количестве обращений к форуму будет заметно.
Vladson, я тоже за твой вариант. Я в принципе считаю, что хорошей структуризацией можно решить и вопрос производительности, и расширяемости.
Выскажусь и я, т.к. свой форум я тоже писал, ни на какие примеры не смотрел, проэктировал сам с 0 с условием максимальной удобности и скорости. Получилось так: [sql] CREATE TABLE forums_areas ( far_id int(11) unsigned NOT NULL auto_increment, far_title char(50) NOT NULL default '', far_creation_date datetime NOT NULL, PRIMARY KEY (far_id), KEY far_creation_date (far_creation_date) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED; CREATE TABLE forums ( for_id int(11) unsigned NOT NULL auto_increment, for_far_id int(11) unsigned NOT NULL, for_title char(50) NOT NULL default '', for_creation_date datetime NOT NULL, for_descr char(200) default NULL, for_topics int(11) unsigned NOT NULL default '0', for_messages int(11) unsigned NOT NULL default '0', for_last_frm_id int(11) unsigned NOT NULL default '0', PRIMARY KEY (for_id,for_far_id), UNIQUE KEY for_id (for_id), KEY for_last_frm_id (for_last_frm_id), KEY for_creation_date (for_creation_date), KEY for_far_id (for_far_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED; CREATE TABLE forums_topics ( frt_id int(11) unsigned NOT NULL auto_increment, frt_prf_id int(11) unsigned NOT NULL, frt_for_id int(11) unsigned NOT NULL, frt_creation_date datetime NOT NULL, frt_title char(50) NOT NULL default '', frt_replyes int(11) unsigned NOT NULL default '0', frt_views int(11) unsigned NOT NULL default '1', frt_last_frm_id int(11) unsigned NOT NULL, PRIMARY KEY (frt_id,frt_prf_id,frt_for_id), KEY frt_creation_date (frt_creation_date), KEY frt_last_frm_id (frt_last_frm_id), KEY frt_replyes (frt_replyes), KEY frt_views (frt_views), KEY frt_id (frt_id), KEY frt_prf_id (frt_prf_id), KEY frt_for_id (frt_for_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED; CREATE TABLE forums_messages ( frm_id int(11) unsigned NOT NULL auto_increment, frm_msg text, frm_prf_id int(11) unsigned NOT NULL, frm_creation_date datetime NOT NULL, frm_frt_id int(11) unsigned NOT NULL, frm_for_id int(11) unsigned NOT NULL, PRIMARY KEY (frm_id), KEY frm_creation_date (frm_creation_date), KEY frm_frt_id (frm_frt_id), KEY frm_for_id (frm_for_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; [/sql] Где: forums_areas - таблица разделов, в которых находяться форумы (по типу PHP, Базы данных, Прочее, Работа на нашем форуме ) forums - непосредственно сами названия форумов, привязанные к разделам. forums_topics - таблица с темами, привязана к форумам forums_messages - сами сообщения, привязаны к топикам. Таблицы конечно не полные, там ещё есть куча полей типа статусов (удалено, отредактировано и.т.д.), всяких специфичных вещей для проэкта, но это вам не надо. Основа - выше. Работать удобно и работает быстро. *_prf_id - это id юзера (связка на таблицу с юзерами)
Я бы эти таблицы с вел в одну, или в две, заюзал бы Nested sets для них и получил бы обалденное быстрое решение с произволным уровнем вложенности и структурированности.
Ага, и получиться полей так ~60 как минимум в таблице. Да ещё fixed если... представляешь какая это потеря места? Да и зачем обращаться к общей таблице, что бы отдельно вывести список форумов и список топиков. Получиться одна большая и тяжелая таблица, с огромным кол-вом индексов. Позже опишу подробнее почему сделано так, а не как в VBulletin.
Запутали вы меня немного. Вопрос стоит скорее не в структуре БД всего форума а в одном простом месте. Есть таблица [sql]CREATE TABLE `forum_posts` ( `post_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `topic_id` int(10) unsigned NOT NULL, `user_id` int(10) unsigned NOT NULL, `post_date` int(10) unsigned NOT NULL, `post_text` text NOT NULL, PRIMARY KEY (`post_id`) ) ENGINE=MyISAM;[/sql] Не будет ли поле `post_text` (только о нём речь, больше не о чём) слабым местом и тормозить выборку, и будет ли прибавление в производительности если в одной из таблиц будут только fixed-поля (int/char) а в отдельной таблице dynamic (varchar/text)
Именно об этом я и говорил выше, да, будет, никогда еще две таблицы с отношением 1:1 не работали быстрее одной таблицы, в которой находится все поля сразу; и нет, не будет, ибо типы Fixed/Dynamic почти не влияют на скорость доступа к данным (индексы и там и там имеют одинаковую структуру), преимущество типа Fixed только в большей надежности восстановления данных после сбоя.
Psih В vB одна таблица для форумов и одна для топиков. Я говорил о том, что там две сущности (категории разделов и собственно разделы) сведены в одну таблицу, ибо они по сути одно и то же, просто на главной странице отображаются по-разному. В других форумах (SMF, phpBB) для категорий есть отдельная таблица. Имхо, такое решение чуть менее универсально. P.S. Nested Sets (наконец-то я могу говорить об этом как о чем-то знакомом ) требуют для работы всего 3 (трех) дополнительных целочисленных полей, легко вычисляемых и действительно реально ускоряющих выборки. Небольшая плата за удобство работы с деревом
Просто остальные начали немного "оф-топить" и говорить о рогах, когда я спрашиваю о копытах... Вот это кстати надо будет обсудить где нибудь в отдельном топике (не вижу я там никакого удобства) И доп-полей только два (left и right, поле category_id будет в любом случае не зависимо от выбранной схемы)
Думаю, стоит конкретизировать — удобство выборки и скорость, в противовес сложности перемещения ветви.
Vladson Там еще есть поле level (уровень нода). Поля category_id (я бы назвал его parent_id) в канонической версии NS нет, хотя я за его наличие - надо же как-то восстанавливать дерево после сбоев. Горбунов Олег Я не против отдельной темы.
Я смотрю, тут собрались сплошь форумописатели. Я тоже присоединюсь к обсуждению, т.к. очень долгое время занимался этим же, да и сейчас занимаюсь под настроение. Лично моё мнение (и моя реализация) по сути темы - хранить текст сообщения темы в таблицы тем, а текст ответа, в таблице ответов. Не вижу смысла выносить уникально связанные 1 к 1 данные в разные таблицы. Нормализации это не добавит, производительность только упадёт, никаких преймуществ в таком решении нет. По поводу производительности, я тестировал свой движок на искусственно сгенерированных данных 24М ответов в 600к тем (таблица ответов ~2.5Гб), проблем с генерированием страниц просмотра тем форумов у меня нет, даже при произвольном доступе к произвольной странице форума время генерирования страницы на очень слабом железе не превышало 600мс, при этом узким местом был винт из-за позиционирования головок в поиске данных в огромных таблицах тем и ответов. Про NS у этого способа хранения деревьев очень мало преймуществ, в основном это эффективная выборка малых объёмов данных (ветви, поиск корня), однако это преймущество ценно на больших и очень больших таблицах, в то время как на этих таблицах катастрофически падает скорость модификации данных, даже самое простейшее действие требует серьёзной модификации служебных синтетических индексов.
ONK Насчет NS наверное лучше написать здесь - http://php.ru/forum/viewtopic.php?t=5303 Мы сегодня с dark-demon'ом в чате уже пообщались на тему преимуществ и недостатков Nested Sets... ему почти удалось меня переубедить
Народ может поможите с ускорением такого запроса: [sql] SELECT *, IF((SELECT COUNT(DISTINCT id) FROM artists WHERE country_id=countries.id AND country_id IS NOT NULL GROUP BY country_id)>=1,1,0) AS pid FROM countries [/sql] то есть есть таблица где перечисленны страны [sql] countries [/sql] соответственно что-то около 300.... и есть таблица с авторами [sql] artists [/sql] что-то около 12 000 но далеко не все авторы связаны с определенной страной ... маркировка 1 и 0 необходима в дальнейшем поэтому и строю так .... отказ от IF не ускоряет запрос , что естественно необходимо было промаркировать страны на наличие и отсутствие артистов! данный запрос работает что-то около 1,1200 секунды ... имхо - много ...
ну и как обычно сам и отвечу ... в таблице [sql]artists[/sql] небыло проиндексированно поле [sql]country_id[/sql] соответственно если добавить индекс на это поле ... то скорость запроса стало составлять 0.0031 сек прошу прощенье за глупые вопросы!
Vladson. Советую ознакомиться со структурой базы в CMS Drupal. Там база реализована по принципу "все в одной таблице". Так вот, при посещаемости в 2к сервер под эту базу нужен уже отдельный...
По исходному вопросу - разделение полезно, если есть много запросов, где не нужен сам текст сообщения. последние сообщения, количество постов, далее по списку. разделять запросы если нужен текст не стоит, в один запрос обе таблицы.