4

Я создаю базу данных для хранения некоторых сообщений в блоге в MySQL. Недавно я наткнулся на эту answer, который сообщает, что, когда у вас есть:Сколько стоит развязывать таблицы в MySQL, улучшая производительность?

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

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

CREATE TABLE article (
    id INT(10) UNSIGNED, 
    title VARCHAR(40), 
    author_id INT(10) UNIGNED, 
    created DATETIME, 
    modified DATETIME 
); 

CREATE TABLE article_text (
    id INT(10) UNSIGNED, 
    body TEXT 
); 

Влияет ли это производительность, даже если столбец не является частью запроса:

SELECT id, title FROM article WHERE author_id=33 ORDER BY created DESC LIMIT 5 

И в каком масштабе она становится проблемой производительности? (Несколько сотен, тысяч? Миллионы?)

+0

Помните, что 'TEXT' по умолчанию довольно пенитен. Возможно, вы хотите, чтобы «LONGTEXT» был в безопасности. – tadman

ответ

7

С MySQL 5.5 и более поздними версиями механизм хранения InnoDB поддерживает Barracuda file format. Чтобы использовать формат файла Barracuda для InnoDB, вы должны использовать табличное пространство для таблицы или использовать общее табличное пространство (однофайловая система «InnoDB tablespace НЕ поддерживает Barracuda»).

До Барракуда (Антилопа), MySQL always stored at least the first 768 bytes of a TEXT column in the clustered (primary key) index. В этом случае, имея столбец TEXT, даже если он не ссылается на него, увеличивается размер каждой строки в кластерном индексе (листовые узлы). Это замедлило сканирование таблицы на других столбцах, отличных от TEXT, поскольку на каждой странице меньше страниц (больше страниц для сканирования в среднем, чтобы найти то, что вы ищете), но при увеличении производительности при сканировании столбца TEXT (первые 768 байт в любом случае) , Вы много сканируете по столу? Надеемся, вы сможете использовать индексы, чтобы избежать сканирования таблиц.

Индексы b-trees, а поиск ключей выполняется на внутренних узлах, содержащих только ключ. Для кластерного индекса это только первичный ключ, поэтому поиск в кластерном индексе не зависит от количества данных в листовом узле (но зависит от размера первичного ключа).

С файловой системой Barracuda для InnoDB весь столбец TEXT хранится в переполненных страницах (которые могут быть сжаты). Никакая его часть не хранится в кластерном индексе (листовые узлы). Итак, если вы используете файловую систему Barracuda, дайте MySQL сделать разделение для вас и просто поместите столбец TEXT в ту же таблицу. В этом случае вы ничего не набираете, поскольку MYSQL уже помещает столбец TEXT в другое место и не влияет на сканирование столбцов, отличных от TEXT.

Если вы используете Antelope, вы можете рассмотреть возможность его разделения, если вы часто просматриваете столбцы не-ТЕКСТ (что вам следует избегать в любом случае), и вы редко ссылаетесь на столбец TEXT. Разделив его на две таблицы, чтобы прочитать всю запись, теперь вам нужно выполнять поиск по двум кластерным индексам, что в два раза дороже одного.

Я также мог видеть, как разделить его с Antelope на системе, где MySQL имеет ограниченную RAM для пространства буфера InnoDB, и вы редко ссылаетесь на столбец TEXT. Листовые узлы, содержащие столбцы, отличные от TEXT, с большей вероятностью останутся в памяти, если они будут меньше.

+1

Хорошие замечания о важных изменениях в MySQL 5.5. – tadman

+0

Я буду спорить с одним утверждением - все индексирование основано на BTrees, а не на двоичном поиске. Миллиард строк может иметь 3 уровня в своем BTree; эта глубина вряд ли будет расти/уменьшаться даже при изменении строки на 768 байт. Я предлагаю, чтобы время поиска для точечного запроса было почти идентичным. –

+0

@RickJames, это правда. Я обновил свой ответ. –

0

Да на все ваши вопросы.

«Вертикальное разбиение» (построение «параллельной таблицы») полезно, когда TEXT (или BLOB и т. Д.) Не всегда требуется.

Если вам не нужен TEXT, он лучше работает из-за меньшего объема в этой таблице.

Когда вам понадобится TEXT, вы, вероятно, получаете только одну (или очень мало) строк, поэтому JOIN в дополнительную таблицу не является значительно дорогостоящим.

У меня есть две базы данных, каждая из которых содержит 200 тыс. Строк, разделенных так. Оба очень хорошо масштабируются. Я бы ожидал, что миллионы, даже миллиарды, не будут проблемой. (Ну, «миллиарды» имеют множество проблем, но вертикальное разбиение является одним из решений.)

Для вашего примера SELECT нужен «составной» ИНДЕКС (author_id, созданный) для масштабирования. Но это не зависит от вертикального разбиения.

+0

Если вы не выполняете 'SELECT *', накладные расходы в столбце 'TEXT' обычно умеренные. - объясняет Маркус. – tadman

+1

5 комментариев от @Marcus Adams действительны; У меня нет прямого опыта сравнения. (Мои таблицы были построены через 5.1 дня.) –

+0

Абсолютно. Я построил крупномасштабную схему именно так, потому что она датируется той эпохой, но теперь я просто встроил их, чтобы избежать беспорядка, который создает. (На самом деле, я бы использовал Postgres, но это еще одна проблема.) – tadman