Как стать автором
Обновить

Комментарии 21

Ура! Поздравляю с новой версией!

записи таблиц, содержащие поля с типом VARCHAR(N) хранятся компактнее, если N достаточно велико

Я-то думал, что у varchar(N), N - всего лишь ограничение при валидации поля, а реально строка хранится как пара (длина, массив[длина])

А на самом деле что, строка всегда добивается пробелами (нулями) до N?

Я-то думал, что разницы не будет, объявлять столбец в таблице как varchar(100) или varchar(200), если используется не более 50. А оказывается, не надо делать объявления "про запас".

С другой стороны, изменение типа столбца с varchar(100) на varchar(200) происходит довольно быстро, не похоже, что страницы с данными перезаписываются. То есть, движок умеет читать сохранённый varchar(100), когда по описанию столбца ожидается varchar(200). Ну и зачем тогда в страницу писать лишних 200 пробелов и сжимать их RLE, если можно записать столько, сколько есть в строке, а движок сконвертирует при чтении.

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

Что касается смены тип с varchar(100) на varchar(200), то это происходит быстро потому что в реальности записи на диске вообще не изменяются. Просто записывается новый формат таблицы, а при извлечении данных записи со старым форматом преобразуются к новому на лету.

Ну вот такая идея. Если в поле с типом varchar(200) реально записан 1 символ, в страницу писать, как будто это было поле varchar(1). Неужели это медленнее, чем RLE-шить 200 знаков?
Вроде как переаллокаций не нужно, ведь читатель страницы не знает, что там будет varchar(1) и заранее аллоцирует 200. Для ввода этой фичи даже ODS менять не надо.

Из курсора читается обычно не одна запись. Предположим в первой записи один символ, а во второй 200, в третьей 50. Предлагаешь на каждом фетче буфер переаллоцировать? Сейчас переаллокаций не происходит вообще. Выделяется буфер фиксированного размера и в нем просто перезаписываются байтики.

Буфер всегда под varchar(200), как указано в описании поля таблицы.

Если же физически в странице varchar(100), сейчас движок что делает? Как-то распаковывает без переаллоцирования. А что ему мешает так же распаковывать то из varchar(4), то из varchar(1), с разных записей разные длины.

Во-первых сжимаются не отдельные varchar, а запись целиком. То есть потенциально могут быть сжаты и другие типы данных если там null.

Во-вторых как я уже говорил кодирование в зависимости от типа данных пробовалось и оно оказалось медленней. Возможно где-то что-то упустили. Но факт остается фактом.

И в-третьих, firebird 5.0 не вводит новую мажорную ods. RLE использовался еще со времен interbase, просто сейчас его усовершенствовали. Таким образом 5 ка может работать с базами данных 4 ки.

В будущих версиях сжатие/ кодирование записи может изменится.

Тогда удивительно, как работает alter column.
Допустим, была запись

(NAME VARCHAR(30), GENDER INT)

это значит, что 30 байт строка, за ней число.
сделали

ALTER COLUMN NAME TYPE VARCHAR(50)

Движок теперь считает, что после распаковки записи, GENDER надо искать не по смещению 30, а по смещению 50. Но когда он читает старую запись со старой страницы, как он понимает, что смещение 30? В базе хранятся все версии метаданных и у каждой записи есть ссылка на версию?

Каждая запись хранит номер формата (1 байт). Формат записи содержит все необходимые сведения для декодирования записи в том числе типы и смещения. Но когда для таблицы делаешь alter более 255 раз будет больно (либо бекап рестор, либо пересоздание таблицы с полной перезаливкой данных). Впрочем не любой alter меняет формат. Это одна из особенностей фб, которая с одной стороны позволяет делать быстрый alter таблицы без ее блокировки, но с другой ограничивает полет фантазий разработчика.

Значит, ничего не поделать. Придётся при указании размера varchar(N) постоянно пребывать в сомнениях: а не мало ли я выбрал, а не много ли...

Соединение потоков с помощью алгоритма HASH JOIN появилось в Firebird 3.0

Было бы круто иметь синтаксис, как в SQL Server, с явным указанием алгоритма:

inner HASH join table1
left LOOP join table2
outer MERGE join table3

В ручных оптимизациях этим можно пользоваться.

Это нестандартно и не переносимо, поэтому такого точно не будет, а вот поддержка хинтов Аля оракул не помешала бы.

Ваше дело, конечно.
Но подумайте о программистах. В трёхстраничном запросе сопоставлять join-ы где-то из середины страницы и хинтами в шапке. Напутать можно. А если хинты привязаны к тому месту, где они применяются, всё гораздо прозрачнее. То же самое с хинтами по индексам в SQL Server.

ну есть хинты ms style - в самих джоинах, есть хинты oracle stype - все в коментах в начале, а есть хинты postgres style :/

Полный синтаксис создания индекса выглядит следующим образом

Как будто синтаксис дополнился указанием направлением сортировки перед словом INDEX
А есть ли разница между

CREATE DESC INDEX horse_deathdate ON horse(deathdate)

и классическим

CREATE INDEX horse_deathdate ON horse(deathdate DESC)

Не знаю где вы этот "классический" вариант нашли. Его в Firebird с роду не было. Направление всегда указывалось для всего индекса, а не отдельного столбца.

А дополнился синтаксис предложением where, которое фильтрует ключи записей по некоторому условию. Те что не соответствуют предикату просто не будут попадать в индекс.

Не знаю где вы этот "классический" вариант нашли

В том же SQL Server. Я думал, оно в стандарте ))

Его в Firebird срроду не было

Тогда печаль. Иногда супер-важно, для каждого столбца задать своё направление упорядочивания.

Microsoft SQL Server в некоторых случаях далек от SQL стандарта. В прочем ни один он, все так или иначе отклоняются от стандарта, ибо стандарт обычно формируется постфактум, когда коммерческие субд уже реализовали некоторую фичу и пропихивают ее в стандарт.

Просто пример, где это удобно:

create index OBJ_LAST_VERSION on OBJECTS (OBJECT_ID, VERSION desc);

select first 1 * from OBJECTS where OBJECT_ID=:objId order by VERSION desc;

Тут для столбца VERSION задана обратная сортировка для выборки последней версии указанного объекта.
Поэтому будет чтение строго одной записи из индекса, а не вычитываение всех записей по OBJECT_ID, а потом сортировка во внутреннем буфере и возврат первой строки, как если бы на VERSION не стоял DESC.
Впрочем, наверное можно обойти COMPUTED BY полем, но не каждый догадается, как.

По синдрому утенка прям любимая СУБД - отрадно, что живёт-развивается.

Автору спасибище за подробности

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации