Из чего состоят строки в базе данных
Что проверяют
Знаете ли вы, что лежит под таблицей: из чего физически состоит запись и почему UPDATE в PostgreSQL не меняет строку на месте. Формулировка двусмысленная, поэтому сначала уточните, о чём речь: о строках таблицы или о строковых типах. Следом обычно спрашивают про MVCC и VACUUM, а для Go ещё и про работу с Rows.
Как отвечать
Если речь о строках таблицы, отвечайте на примере PostgreSQL:
- страница: данные лежат в страницах по 8 КБ, в начале массив указателей на строки, сами строки заполняют страницу с конца;
- заголовок: 23 байта служебных данных.
xminиxmaxэто номера транзакций, создавшей и удалившей версию,ctidеё физический адрес, дальше флаги; - битовая карта NULL: появляется, только если в строке есть
NULL, по биту на столбец. СамNULLместа под значение не занимает; - данные: значения столбцов подряд с выравниванием по типу. Порядок столбцов влияет на размер:
boolмежду двумяbigintдаст 7 байт пустоты; - TOAST: значения длиннее примерно 2 КБ сжимаются и выносятся в отдельную таблицу, в строке остаётся ссылка.
UPDATE создаёт новую версию строки, старая становится мёртвой и ждёт VACUUM. Для сравнения, в InnoDB строки лежат в кластерном индексе по первичному ключу со скрытыми полями транзакции и указателя отката, а старые версии уходят в undo-лог.
Со стороны Go результат приходит как *sql.Rows или pgx.Rows. Правильный цикл: defer rows.Close(), rows.Next() и rows.Scan(...), после цикла проверка rows.Err(). В pgx удобно pgx.CollectRows с pgx.RowToStructByName.
Если спрашивали про строковые типы: text и varchar в PostgreSQL хранятся одинаково, а char(n) дополняет пробелами и выгоды не даёт.
Где спотыкаются
Отвечают про VARCHAR, когда спрашивали про устройство записи, и наоборот. Уточняющий вопрос в начале экономит весь ответ.
Не закрывают Rows. Соединение не возвращается в пул, и под нагрузкой сервис упирается в лимит соединений.
Сканируют NULL в обычный string и получают ошибку. Нужны sql.NullString, *string или pgtype.Text.