Pull to refresh

Comments 15

А можно пользуясь случаем спросить? В бинарном формате массивов со значениями элементов передаётся некое поле lBound. Практика показала что обычно оно равно единице, но не всегда. В чём его смысл? Важно ли оно для прикладного использования или это внутреннее поле Postgres и его можно игнорировать при чтении из БД и записи в неё?

нижняя граница массива, по умолчанию 1. Например формат: {10,20,30} - нумерация с единички, то же самое, что:

Формат [3]={10,20,30} - нумерация с единички.(lBound=1) int[1]=10 /* [n] format */

Формат [2:6]={10,20,30} - нумерация с двойки (lBound=2) int[2]=10 /* [m:n] format */

На странице 3 учебника https://edu.postgrespro.ru/16/dev1-16/dev1_15_plpgsql_arrays.html есть примеры в другую сторону - инициализации и вывода, а не сканирования массива с единички:

a := ARRAY[10,20,30];
    RAISE NOTICE '%', a;
    -- по умолчанию элементы нумеруются с единицы

lBound=2:

    a integer[];
BEGIN
    a[2] := 10;
    a[3] := 20;
    a[6] := 30;

смотря как работать с массивом. При доступе по индексу массив[индекс] важно, так как влияет на нумерацию элементов

Спасибо!

Интересно почему так сделан доступ по индексу внутри SQL? Ведь если мы делаем слайс значит мы хотим работать (или вернуть) только с частью массива, без учета общего его размера

Риторический вопрос, понятное дело. Просто так сложилось когда-то в 80-е

Можно использовать FOREACH x IN ARRAY a LOOP, где индекс не важен и границы у a не играют роли. Я для себя не сразу понял: если мне что-то кажется неестественным в PostgreSQL, то значит я что-то не понимаю или для этого были причины. Философски: с массивами может быть переносится логика повышенного контроля - хочу прямо указать индекс, а лучше в итеративном стиле - просматривать всё, SQL декларативен, а не императивен

Если в строке хотя бы одно из полей пусто (имеет значение NULL), то в заголовке этой строки выделяется место под битовую карту.

Как забавно... это получается, что вульгарное

UPDATE table SET column = NULL

приводит к увеличению длины заголовка записи, если до того все поля были NOT NULL, и в принципе (если значение column занимало меньше места, чем добавляемая битовая карта) способно привести даже к расщеплению блока хранения, если с добавлением битовой карты объём занятого в блоке пространства превысит порог расщепления?

 Это значит, что при прочих равных, если в каком-то из столбцов возможно пустое значение, то лучше создать таблицу с 8 столбцами, а не 9.

Убийственная какая-то фраза... вообще-то если нужна таблица с 9 полями, то создание вместо неё таблицы с 8 полями - крайне странное мероприятие вне зависимости от цели этого мероприятия. Тем более если это делается ради экономии одного байта.

Размеры существующих строк не меняются. При обновлении созаются новые версии строк. Если есть место в блоке с прежней версией, то в нём и устанавливает бит Heap Hot Updated на прежней версии строки. Если нет места, то в блоке, где есть свободное место.
Если нужна таблица с 9 столбуами, то делают с 9 столбцами. Фраза для проектировщиков схем. У них встречаются задачи спроектировать таблицу с flex-fields (гибкие поля). Первыми идут необходимые столбцы, например 5 штук, а потом проектируются стобцы ATTRIB_1..15 или ATTRIB1..39. И у них есть выбор сделать 15 столбцов или 14. Столбцы создаются с запасом и большинство заполняется null.

А в чём смысл кроить на этих байтах? Сейчас SSD относительно дешёвые, уже даже не вспоминают про решения типа Stacker и DoubleSpace.

А про влияние на быстродействие базы вы не написали.

если объемы маленькие можно и в Excel хранить ) тоже иногда думаю, что чем больше таблица и база тем лучше - можно говорить что работал с большой базой. ) Обращать внимание на NULL не первоочередная задача оптимизации. Одна из причин написания статьи: те кто работал с Oracle знают, что лучше избегать использование NULL утсанавливая ограничения целостности хотя бы потому, что NULL в Oracle Database не индексируются и если в запросе не стоит AND IS NOT NULL или нет ограничения NOT NULL, то идёт полное сканирование таблицы. Переносить на PostgreSQL эту логику неверно. Статья чтобы узнать про особенности хранения NULL и делать поправку зная как PostgtreSQL работает с NULL. И использование NULL в PostgreSQL экономит место. Например, тип timetz занимает 12 байт, interval 16 байт, int8 8 байт даже для чисел 0 и -1. Можно запроектировать хранить значение со смыслом "отсутствует" как NULL или использовать "-1". Экономия может быть 8 байт на строку, что существенно.

Всё ещё хотелось бы услышать не про экономию 8 байт на строку, а про влияние на эффективность. Предполагаю, что идёт на пользу :-), но вы почему-то ничего про это не написали.

А о каком влиянии на эффективность может идти речь? Что именно вы предлагаете сравнивать-то?

Описанная схема хранения - есть, другой - нет. Сравнивать-то не с чем...

Или вы предлагаете сравнить варианты "использовать NULL" и "использовать преопределённую константу с невозможным значением" (как пример - ноль, MAXINT, или там пустая строка)? А тут всё упрётся в конкретный текст запроса.

Именно. Раз уж вы проповедуете "используйте NULL, он хранится эффективно" – сравнивайте по эффективности запросов.
А если "упрётся в конкретный текст запроса" – то так и пишите: мол, вот для таких запросов NULL использовать выгодно, а для сяких – лучше его избегать.

Эммм... вы хоть на ники посматривайте, что ли.

А, извините, упустил, что собеседник поменялся – так вы нить разговора аккуратно подхватили :-)

Про эффективность - хорошая идея ) Если не будет идей, можно показать как уменьшается производительность. Но думаю, это не практино, так как можно показать эффективность от небольшой до десятка раз (как время выполнения, так и tps).

Вы думаете, что экономия 8 байт на строку, а это не так. Я приводил картинки со столбцом с названием ATTRIB_47. Представим два варианта: возможны NULL и 47 полей ATTRIB_1..47 не занимают место, если заполнены NULL , что показано в статье. Второй вариант - добавляются ограничения целостности NOT NULL (можно и не добавлять, но для правильности добавим) и поля по умолчанию заполняются значением -1. Тип данных не int4, а сразу bigint. Пусть разработчики PostgreSQL экономят - делают oid и xid 4байтными, мы не крохоборы. Экономия места на строку 47*8= 376 байт. Создадим таблицу с 10 строками - аналог pgbench_tellers. INSERT не покажет ощутимой разницы, поэтому сделаем тест с UPDATE, строка превратися в набор версий строк. Немного удержим горизонт базы, что близко к практической нагрузке и через 100 секунд одна строка будет иметь при 600 tps 6000 предыдущих версий. Разница 6000*376=2.2Мб на 10 строк. Разница в числе строк в блоке существенна для производительности при индексном доступе. Пример замедления показывался в статье про горизонт. Чтобы заниматься настройкой производительности, я думаю, полезно иметь хорошую базу - знать как организовано хранение, архитектуру PostgreSQL. Всё в одну статью не уместить. Там где правила и решения для улучшения производительности простые, они вставляются в ядро PostgreSQL и с каждой новой версией PostgreSQL работает быстрее.

Для сравнения эффективности/скорости нужно иметь методику сбора и анализа статистических данных.

И моя любимая фраза - "прежде всего нужно определить - что такое производительность СУБД и как ее считать ".

Sign up to leave a comment.

Articles