Здравствуйте, MozgC, Вы писали:
MC>Поговорил тут с одним специалистом, очень хорошо на мой взгляд разбирающимся в БД.
Ну, это на Ваш взгляд (дальше конкретизирую)...
MC>Он говорит что всегда в таких случаях, когда определенные столбцы используются редко, выносит эти столбцы в отдельную таблицу.
Я тоже могу сказать, что жену пять раз в день "удовлетворяю"... Ну и Вы говорите! Кто запрещает?!
MC>Основные причины:
MC>1) Уменьшение размера базы данных. Так как в большинстве случаев используется фиксированный размер строк, поэтому если в таблице с миллионом строк указано только 10% комментариев (varchar(250)), то экономия размера базы будет — сотни мегабайт (примерно от 235 Мб до более полугигабайта в зависимости от используемой кодировки).
Выносить данные в отдельную (связанную по первичному ключу) таблицу нужно только в случае действительно реальной экономии! Это работает действительно только на сверхбольших базах. Вообще-то, база читается в ОП страницами и блоками, независимо практически от самой структуры БД... Тут надо понимать, что "движки" современных серверов БД — они над "файл-системные", т.е. в любом современном движке СУБД присутствует уровень абстракции над конкретной файловой системой. Будь то "Виндоза", или "Линух", или МВС... Тут надо ещё и "физику" смотреть... Реально, честно говоря, платформа имеет значение. Даже аппаратная конфигурация... Да даже "группы файлов", и физическое расположение дисков и уровни РАИД-а! Если база многфайловая и физически располагается на разных дисках...
MC>2) Ускорение чтения (и записи) с жесткого диска. Допустим чтение происходит блоками по 8К и размер записи — N, тогда в 1 блоке уместится 8К/N записей в случае если комментарий у нас в общей таблице и 8K/(N-250) если комментарий в отдельной таблице. С одной стороны зачастую практически вся БД может находиться в кеше, с другой стороны даже в таком случае время от времени происходит сохранение из кеша на жесткий диск, т.е. некоторая разница все равно будет.
Нет. Вся БД может находиться в кэше только в случае, если БД размером в десяток мегабайт... А так для многих современных алгоритмов кэширования БД 4-6% от физического размера БД в кэше (в ОП сервера БД) — это уже более чем достаточно, и дальнейшее увеличение размеров кеширования страниц БД в ОП — выйгрышь по экспоненте резко сокращается... Тут опять же работает то самое пресловутое Правило Паретто (20/80)...
MC>3) Ускорение выполнения некоторых запросов, иногда многократное ускорение. И речь идет не только о случае с SELECT * FROM order_lines когда комментарии не нужны в выборке.
MC>Допустим заполнен малый процент комментариев. И нужно выбрать все комментарии за сегодня. В случае когда комментарии находятся в той же таблице запрос будет такой:
MC>SELECT ... FROM order_lines WHERE Comment IS NOT NULL AND CAST(TSComment AS DATE) = '2009-11-02'
MC>Будет перебрана куча записей, чтобы найти требуемые записи с комментариями.
Я не знаю, на что ориентирован Ваш "эксперт по БД", но ещё на первых курсах по Ораклу говорится, что выражение "IS NOT NULL" в "where" автоматически
вырубает все схемы оптимизаторов запросов и идёт "тупой" и прямолинейный "Full Scan"... Ну нет в реляционной алгебре и движках такой мат.конструкции, как проверка "на наличие пустоты"! Я могу ошибаться, но насколько я знаю, даже в "движках" БД MS SQL Server и MySQL всех версий конструкции в "WHERE", типа "IS NOT NULL" надо избегать, т.к. они
не реляционные! Я бы в данном случае просто внёс бы в основную таблицу два поля (колонки):
1. Однобайтовую (Fixed(1)), как признак наличия комментария (или какой-то другой однобайтовый флаг).
2. Дату последнего комментария (может быть и NULL значения по-умолчанию).
А сами комментарии вынес бы в отдельную таблицу, связанную по первичному ключу... Доступ к комментариям обычно нужен не в "сплошном" запросе, а конкретно "позаписно", когда нужно в отдельном экране его отобразить...
MC>Такая выборка будет заметно менее быстрой чем в случае когда комментарии хранятся в отдельной таблице:
MC>SELECT ... FROM order_line_comments INNER JOIN order_lines ON (...) WHERE CAST(TSComment AS DATE) = '2009-11-02'
MC>Разница в скорости в таких запросах скорее всего будет в разы.
Вообще-то, "будем посмотреть"... CAST вообще надо избегать... Я вообще-то иногда ввожу в базы некоторые Fixed(1) "флаги" о "наличии присутствия" того или иного события (факта)... Хоть это и нарушает правила нормализации, но существенно ускоряет работу в БД! Например, дату закрытия заказа платёжкой я дополняю просто полем самого факта закрытия строки заказа (логическим или фиксированным однобайтовым "Х" или "1"). А если такое поле входит в какой-либо индекс, то уже нет надобности делать запрос
только по датам в выражении "where", оптимизатор "по факту (атрибуту, флагу) отфильтрует все записи из таблицы ("закрытые заказы"), а уж потом их будет анализировать на дату (интервал или равенство)... Тут надо ещё смотреть, какую степень селективности индексы имеют! Дело в том, что многие оптимизаторы СУБД просто игнорируют построенные индексы, если у них низкая степень селективности... Короче, "физические алгоритмы оптимизаторов" могут выбрать такой план, что индексы ВООБЩЕ не будут использоваться! Это особенно для DB2 и Oracle характерно! Поверьте! Перенесение "чиста десктоповского" опыта на СУБД промышленного масштаба не работает! Там ещё и РАИД-ы надо учитывать... Да и вообще — "железо"!
MC>4) Разносим индексы по разным таблицам. Во-первых, теперь индексы будут обновляться реже: к примеру при вставке записи без комментария индексы в таблице комментариев не трогаются. Во-вторых, в некоторых СУБД будет и сокращение размеров индексов (к примеру в SQL Server индексы включают указатели на строки с null-значением индексируемого столбца, соответственно индекс по Comment в таблице order_lines будет намного больше, чем индекс по Comment в таблице order_line_comments).
Это хорошо, если так... Но обычно "NULL-поля" вообще в индекс не попадают... А это уже очень интересная ситуация... Но, опять же, всё зависит от движка... "IS NULL" многие "движки" принимают в расчёт во время запроса, а вот "NOT is null" игнорируют и делают оптимизацию плана по другим критериям — частенько просто тупо сканируют базу... Надо смотреть! О какой базе вообще речь идёт?
MC>Ну вот такие вот мысли.
Хорошие мысли. Не глупые. Только у советчика спросите обязательно: он про какую базу речь вёл? Ибо это важно!