За последние 24 часа нас посетили 22777 программистов и 1257 роботов. Сейчас ищут 716 программистов ...

Вопрос быстродействия...

Тема в разделе "MySQL", создана пользователем Vladson, 30 мар 2007.

  1. Vladson

    Vladson Старожил

    С нами с:
    4 фев 2006
    Сообщения:
    4.040
    Симпатии:
    26
    Адрес:
    Estonia, Tallinn
    Вот в нашем любимом 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]

    Знаю что для человека с моим количеством сообщений вопрос кажется глуповат, но я реально не знаю (и хотел бы узнать, на рнр-клубе было подобное обсуждение, но на сколько я помню так там ни к чему и не пришли)
     
  2. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.153
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    :? одна таблица с индексами для ускорения выборки и один запрос быстрее чем две таблицы. наверное :D
    ведь чем больше таблиц тем больше обращений к жёсткому диску, при множестве запросов на выборку получим бутылочное горлышко в виде жёсткого диска.

    а на самом деле надо померять скорость на реальной задачке. иначе все оценки субъективны.
     
  3. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    Vladson
    Имхо, смысла в этом нет. Просто сделали "на всякий случай" отдельную таблицу :?
    Я мог бы сказать, что смысл в этом есть, если бы в одной таблице все поля были бы фиксированной ширины (соответственно тип таблицы MyISAM Fixed), а в другой - произвольной (MyISAM Dynamic). В случае крэша данных первую таблицу было бы легче восстановить. Но, насколько я помню, там и в первой таблице тоже есть текстовые поля (имя автора, заголовок сообщения), да и нафиг восстанавливать только одну таблицу когда во второй самые важные данные? В общем это ошибка проектирования имхо, и очень жаль что они ее протащили из phpBB в phpBB2.
     
  4. Vladson

    Vladson Старожил

    С нами с:
    4 фев 2006
    Сообщения:
    4.040
    Симпатии:
    26
    Адрес:
    Estonia, Tallinn
    Вопрос не столько в phpBB сколько в том стоит ли повторять их ошибку при написании другого форума...

    Дело в том что при проектировании БД я столкнулся с тем что удобнее делать всё в одной таблице, но вот при большом размере таблицы не будет ли тормозов ? (при условии что выборка идёт только по int полям)

    PS я не делаю форум (нет финансирования) пока только в мечтах проектирую, хз будет ли когда нибудь время/деньги написать :)
     
  5. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    Vladson
    Нет. Однозначно, повторять эту ошибку только потому, что "другие так сделали" не нужно.
     
  6. Vladson

    Vladson Старожил

    С нами с:
    4 фев 2006
    Сообщения:
    4.040
    Симпатии:
    26
    Адрес:
    Estonia, Tallinn
    Dagdamor
    С радостью выслушаю другие мнения (если они есть) но пока мне кажется что вы абсолютно правы.
    (я с самого начала подозревал что это так, но слепо быть уверенным в том чего не знаю я не привык)
     
  7. DarkElf

    DarkElf Активный пользователь

    С нами с:
    22 окт 2006
    Сообщения:
    1.632
    Симпатии:
    0
    Вероятно, стоит все таки разделить таблицу постов, таблицу топиков и таблицу структуры.

    ибо таблица топов обновляется заметно реже таблицы постов, не говоря уже о структуре.

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

    Anonymous Guest

    Vladson, я тоже за твой вариант. Я в принципе считаю, что хорошей структуризацией можно решить и вопрос производительности, и расширяемости.
     
  9. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Выскажусь и я, т.к. свой форум я тоже писал, ни на какие примеры не смотрел, проэктировал сам с 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 юзера (связка на таблицу с юзерами)
     
  10. Anonymous

    Anonymous Guest

    Я бы эти таблицы с вел в одну, или в две, заюзал бы Nested sets для них и получил бы обалденное быстрое решение с произволным уровнем вложенности и структурированности.
     
  11. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    Горбунов Олег
    +1. В vBulletin так и реализовано (правда без NS ;)), очень удобно для больших форумов.
     
  12. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    6
    Адрес:
    Рига, Латвия
    Ага, и получиться полей так ~60 как минимум в таблице. Да ещё fixed если... представляешь какая это потеря места?
    Да и зачем обращаться к общей таблице, что бы отдельно вывести список форумов и список топиков. Получиться одна большая и тяжелая таблица, с огромным кол-вом индексов.

    Позже опишу подробнее почему сделано так, а не как в VBulletin.
     
  13. Vladson

    Vladson Старожил

    С нами с:
    4 фев 2006
    Сообщения:
    4.040
    Симпатии:
    26
    Адрес:
    Estonia, Tallinn
    Запутали вы меня немного. Вопрос стоит скорее не в структуре БД всего форума а в одном простом месте.

    Есть таблица
    [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)
     
  14. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    Именно об этом я и говорил выше, да, будет, никогда еще две таблицы с отношением 1:1 не работали быстрее одной таблицы, в которой находится все поля сразу; и нет, не будет, ибо типы Fixed/Dynamic почти не влияют на скорость доступа к данным (индексы и там и там имеют одинаковую структуру), преимущество типа Fixed только в большей надежности восстановления данных после сбоя.
     
  15. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    Psih
    В vB одна таблица для форумов и одна для топиков. Я говорил о том, что там две сущности (категории разделов и собственно разделы) сведены в одну таблицу, ибо они по сути одно и то же, просто на главной странице отображаются по-разному. В других форумах (SMF, phpBB) для категорий есть отдельная таблица. Имхо, такое решение чуть менее универсально.

    P.S. Nested Sets (наконец-то я могу говорить об этом как о чем-то знакомом :D) требуют для работы всего 3 (трех) дополнительных целочисленных полей, легко вычисляемых и действительно реально ускоряющих выборки. Небольшая плата за удобство работы с деревом :)
     
  16. Vladson

    Vladson Старожил

    С нами с:
    4 фев 2006
    Сообщения:
    4.040
    Симпатии:
    26
    Адрес:
    Estonia, Tallinn
    Просто остальные начали немного "оф-топить" и говорить о рогах, когда я спрашиваю о копытах...
    Вот это кстати надо будет обсудить где нибудь в отдельном топике (не вижу я там никакого удобства)
    И доп-полей только два (left и right, поле category_id будет в любом случае не зависимо от выбранной схемы)
     
  17. Anonymous

    Anonymous Guest

    Думаю, стоит конкретизировать — удобство выборки и скорость, в противовес сложности перемещения ветви.
     
  18. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    Vladson
    Там еще есть поле level (уровень нода).
    Поля category_id (я бы назвал его parent_id) в канонической версии NS нет, хотя я за его наличие - надо же как-то восстанавливать дерево после сбоев.

    Горбунов Олег
    Я не против отдельной темы. :)
     
  19. Vladson

    Vladson Старожил

    С нами с:
    4 фев 2006
    Сообщения:
    4.040
    Симпатии:
    26
    Адрес:
    Estonia, Tallinn
  20. ONK

    ONK Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    281
    Симпатии:
    0
    Адрес:
    СПб
    Я смотрю, тут собрались сплошь форумописатели. ;) Я тоже присоединюсь к обсуждению, т.к. очень долгое время занимался этим же, да и сейчас занимаюсь под настроение.
    Лично моё мнение (и моя реализация) по сути темы - хранить текст сообщения темы в таблицы тем, а текст ответа, в таблице ответов. Не вижу смысла выносить уникально связанные 1 к 1 данные в разные таблицы. Нормализации это не добавит, производительность только упадёт, никаких преймуществ в таком решении нет.
    По поводу производительности, я тестировал свой движок на искусственно сгенерированных данных 24М ответов в 600к тем (таблица ответов ~2.5Гб), проблем с генерированием страниц просмотра тем форумов у меня нет, даже при произвольном доступе к произвольной странице форума время генерирования страницы на очень слабом железе не превышало 600мс, при этом узким местом был винт из-за позиционирования головок в поиске данных в огромных таблицах тем и ответов.

    Про NS у этого способа хранения деревьев очень мало преймуществ, в основном это эффективная выборка малых объёмов данных (ветви, поиск корня), однако это преймущество ценно на больших и очень больших таблицах, в то время как на этих таблицах катастрофически падает скорость модификации данных, даже самое простейшее действие требует серьёзной модификации служебных синтетических индексов.
     
  21. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    ONK
    Насчет NS наверное лучше написать здесь - http://php.ru/forum/viewtopic.php?t=5303
    Мы сегодня с dark-demon'ом в чате уже пообщались на тему преимуществ и недостатков Nested Sets... ему почти удалось меня переубедить ;)
     
  22. nimistar

    nimistar Активный пользователь

    С нами с:
    30 май 2007
    Сообщения:
    919
    Симпатии:
    0
    Народ может поможите с ускорением такого запроса:
    [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 секунды ... имхо - много ...
     
  23. nimistar

    nimistar Активный пользователь

    С нами с:
    30 май 2007
    Сообщения:
    919
    Симпатии:
    0
    ну и как обычно сам и отвечу ...

    в таблице [sql]artists[/sql] небыло проиндексированно поле [sql]country_id[/sql]

    соответственно если добавить индекс на это поле ... то скорость запроса стало составлять 0.0031 сек

    прошу прощенье за глупые вопросы!
     
  24. Davil

    Davil Guest

    Vladson.
    Советую ознакомиться со структурой базы в CMS Drupal.
    Там база реализована по принципу "все в одной таблице".
    Так вот, при посещаемости в 2к сервер под эту базу нужен уже отдельный...
     
  25. armadillo

    armadillo Активный пользователь

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    По исходному вопросу -
    разделение полезно, если есть много запросов, где не нужен сам текст сообщения.
    последние сообщения, количество постов, далее по списку.
    разделять запросы если нужен текст не стоит, в один запрос обе таблицы.