SELECT x FROM таблица с огромными полями. Создать ли отдельную таблицу с x для оптимизации?
Всем привет, ситуация такая.
На сайте с книгами есть таблица chapters с полями book_id (ключ на другую таблицу), chapter_title (название главы), chapter_text (текст главы).
Проблема в том, что поле chapter_text может содержать огромное количество символов, вплоть до нескольких мегабайт!
Так вот, много где используется запрос SELECT title FROM book_chapters WHERE book_id = XYZ ORDER BY id исключительно для того, чтобы получить и вывести список глав конкретной книги, но сами тексты этих глав не нужны, поэтому я исключил из выборки select то самое гигантское поле текста .
Я где-то читал, что, когда ищется в строке с большим размерами, то требуется больше оперативной памяти и больше времени, даже несмотря на то, что я ограничил SELECT легкими полями.
Поэтому может лучше выделить отдельную таблицу для хранения текста? То есть, может лучше разделить эту таблицу на
легкую chapter_title (id, book_id, title)
и огромную chapter_text (chapter_title_id, chapter_text).
И в итоге для получения списка глав нужно лишь делать запрос к одной очень легкой таблице book_chapter! А к таблице с текстом делать запрос только тогда, когда человек читает.
На данный момент я не замечаю каких-то проблем, ищется по времени нормально, но мало ли, когда народу много, и когда просматривается много тяжелых книг, сайт переодически подвисает из-за этого, а я не в курсе (я совсем не шарю в мониторинге и профайлинге да и в администрировании в целом, только в программировании.)
может лучше выделить отдельную таблицу для хранения текста?
Это обычный вертикальный шардинг. Думаю. есть смысл почитать по нему теорию, а потом принимать решение. И учитывать известную фразу о том, что преждевременная оптимизация есть зло.
Надеюсь индекс (id,book_id, title) у Вас построен ?
Если да и оперативки достаточно, чтобы он целиком оставался в ОЗУ, то
запрос select id,book_id,title выполняется без обращения к диску. Если памяти маловато, то перечитавает с диска только файл индекса.
А вот для индекса только по book_id будет читать и основной файл.
А так ваше предположение сделать кей - валуе хранилище для блобов вполне правильное.
Будет прекрасно работать по первичному ключу.
Но думаю пока дробить нет смысла. Просто пишите код так, чтобы потом можно было легко переделать.
Н-р заведите две константы с одинаковым пока значением
TABLE_CHAPTERS_INFO и TABLE_CHAPTERS_TEXT
А разнесете их физически, после того как захотите добавить еще какие-то поля помимо титла. Н-р размер в байтах и / или листах, дату обновления
Спасибо за ответ!
Индекс у меня только по book_id. Насчет оперативки сложно сказать, у меня сайт на выделенном хостинге :)
То есть, если все нужные мне поля будут в индексной базе, то это будет быстро.
Однако индексов получается будет много, например, есть еще поле sort. На самом деле, полный запрос выглядит так SELECT id, title FROM book_chapters WHERE book_id = ? ORDER BY sort. Значит ли это, что и sort должен быть в индексе?
В общем, если решу все же оптимизировать по полной, то лучше сделаю отдельную таблицу, а индекс пусть будет только на book_id.
На самом деле, полный запрос выглядит так SELECT id, title FROM book_chapters WHERE book_id = ? ORDER BY sort. Значит ли это, что и sort должен быть в индексе?
Оптимальным для показанного запроса является индекс с префиксом (book_id, sort, ...). Поскольку id и title - короткие данные, то оптимальным с точки зрения производительности для именно данного запроса является покрывающий индекс (book_id, sort, id, title).
Однако индексов получается будет много,
Это обычное дело - поиск баланса между производительностью получающих и модифицирующих запросов. С учётом того, что все модификации у тебя либо пакетные, либо интерактивные, в данном случае на производительность модифицирующих запросов скорее всего можно смело забить, и создавать большое количество различных индексов, оптимизирующих извлекающие запросы.
Хм, кажется нашел ответ на свой вопрос вот тут https://stackoverflow.com/questions/13760998/store.... Если есть возможность включить такой параметр innodb_file_format=barracuda, то нет смысла отделять большие тексты в отдельные таблицы - их БД сама уже там будет хранить. Поэтому главное в select просто надо не указывать эти большие поля. Надеюсь, я все правильно понял )
Если есть возможность включить такой параметр innodb_file_format=barracuda
Данный формат доступен на версии 5.7 и старше, причём он вообще там дефолтный, то есть дополнительного явного указания формата вообще не требуется.
А если такой возможности нет, то сервер древний как дерьмо мамонта, и надо срочно обновлять версию сервера.