пятница, 31 августа 2007 г.

column-oriented vs row-oriented DBs

Читаю в последнем номере компьютерных вестей статью про Линтер - российскую СУБД. Честно сказать - веет нафталином. Ну не от самой статьи, а от Линтера. В общем-то вполне понятно, что ничего линтеру не светит - за 10 лет своего существования никакой известности в IT-среде ему достичь не удалось. (Кстати, у американцев есть замечательное слово buzz именно для таких случаев.) Но речь в не о линтере, а о технических решениях, лежащих внутри. Дочитал я до фразы "Данные в таблицах физически хранятся построчно" и сразу внутренне возмутился. Почему это грубейшая ошибка? 

Рассмотрим подробнее: все знают, что внутри процессора есть кэш-память. И назначение этой памяти тоже все знают. Но почему-то никто не задумывается о том, что память эта мала и относиться к её наполнению нужно бережно. Т.е. если СУБД хранит данные построчно, а запрос выбирает одну колонку, то вместе с данными этой колонки в кэш будут попадать и бесполезные куски данных от соседних колонок. А к чему приводит забивание кэша ерундой? К циклам ожидания процессора - он же вынужден ждать данные. К тормозам.
Представим типичную картину: в таблице с двадцатью колонками лежит миллион записей, выполняется запрос типа "select Field1 from Table1 where Field2 = 22", подходящий индекс оптимизатор определить не сумел и запустил full scan. В процессе выполнения этого запроса будут прочитаны с дисков все страницы данных принадлежащие таблице. Что уже само по себе страшно медленная операция: дисковый ввод-вывод, да ещё и забивающий ненужными данными кэш операционной системы. Потом по каждому блоку будет выполнен поиск нужного поля и его сравнение. В процессе поиска будет просаживаться уже кэш процессора, см. выше. И вот типичный результат: мощнейший компьютер потенциально выполняющий на каждом процессоре 2147483648 (и больше) операций в секунду демонстрирует 100% загрузку и вынуждает разработчика тратить время на профилирование индексов и тюнинг плана SQL-запроса.
А как могло бы быть иначе? А вот как: данные нужно хранить не по строкам, а по столбцам. Т.е. данные каждой колонки - в отдельный линейный массив. Из такой системы хранения получается сразу куча преимуществ - и дисковый ввод-вывод экономится, и кэш операционки, и кэш процессора, да ещё и команды поточной обработки данных можно применять. Да! И индекс по этой колонке становится не нужен - скорость работы позволяет обходиться без него! Красота!
Внимательный разработчик сразу скажет: так что же это творится, ведь везде одно и то же - везде работает первый сценарий! И Oracle записи хранит построчно, и MSSQL, и ещё куча остальных. Да, господа, нас самым наглым образом наобманывают (тоже хорошее слово). Свидетельством тому является два факта: нежизнеспособность систем на распространенных СУБД построенных без индексов и существование систем, которые, образно говоря, "бегают вокруг оракла кругами". Например: Kdb, C-StoreMonetDB. Рекомендую ознакомиться хотябы в общеобразовательных целях.
Ещё более внимательный разработчик скажет: так ведь ноги то растут из использования программистом сложных структур данных: record, union и т.д. И объектов само-собой тоже. Что же, их не использовать? Да. Увы, но получается, что когда у вас реально много данных, то от использования структур придется отказаться.
Вот он, секрет быстрого ПО.

2 коммент.:

Mamut комментирует...

> когда у вас реально много данных, то от использования структур придется отказаться

Или использовать базу данных, поддерживающую структуры нативно (Mnesia в Erlang'е, например)

enternet комментирует...

Ну, дело то не в нативности, это системным отладчиком нужно ОЗУ посмотреть, как оно там расположено. 8-)

А вообще - честно сказать, не работал пока с Эрлангом. Смущает идеология, смущает синтаксис, смущает непонятный статус языка - Эриксон от него отказался ещё 15 лет назад, а все кричат что якобы Эриксон его пиарит. О мнезии тоже встречал отзыв - мол, течет память при больших нагрузках.