У меня есть таблица PostgreSQL. select *
очень медленно, в то время select id
как приятно и быстро. Я думаю, что это может быть из-за того, что размер строки очень велик, и для транспортировки требуется время, или это может быть какой-то другой фактор.
Мне нужны все поля (или почти все), поэтому выбор только подмножества не является быстрым решением. Выбор полей, которые я хочу, все еще идет медленно.
Вот моя схема таблицы без имен:
integer | not null default nextval('core_page_id_seq'::regclass)
character varying(255) | not null
character varying(64) | not null
text | default '{}'::text
character varying(255) |
integer | not null default 0
text | default '{}'::text
text |
timestamp with time zone |
integer |
timestamp with time zone |
integer |
Размер текстового поля может быть любым. Но все равно не более нескольких килобайт в худшем случае.
Вопросов
- Есть ли что-нибудь об этом, что кричит «сумасшедший неэффективный»?
- Есть ли способ измерить размер страницы в командной строке Postgres, чтобы помочь мне отладить это?
length(*)
а не простоlength(field)
? Я знаю, что это символы, а не байты, но мне нужно только приблизительное значение.Ответы:
Q2:
way to measure page size
PostgreSQL предоставляет ряд функций размера объектов базы данных . Я собрал наиболее интересные из них в этом запросе и добавил некоторые функции доступа к статистике внизу. (Дополнительный модуль pgstattuple предоставляет еще больше полезных функций.)
Это покажет, что разные методы измерения «размера строки» приводят к очень разным результатам. Все зависит от того, что именно вы хотите измерить.
Этот запрос требует Postgres 9.3 или новее . Для более старых версий см. Ниже.
Использование
VALUES
выражения вLATERAL
подзапросе , чтобы избежать написания вычислений для каждой строки.Замените
public.tbl
(дважды) на необязательное имя таблицы, дополненное схемой, чтобы получить компактное представление собранной статистики о размере ваших строк. Вы можете обернуть это в функцию plpgsql для многократного использования, передать имя таблицы в качестве параметра и использоватьEXECUTE
...Результат:
Для более старых версий (Postgres 9.2 или старше):
Тот же результат.
Q1:
anything inefficient?
Вы можете оптимизировать порядок столбцов, чтобы сохранить несколько байтов на строку, которые в настоящее время тратятся на выравнивание:
Это экономит от 8 до 18 байт на строку. Я называю это «колонна тетрис» . Подробности:
Также учтите:
источник
, unnest(val) / ct
на, (LEAST(unnest(val), unnest(val) * ct)) / (ct - 1 + sign(ct))
и не бросит. Обоснованием является то, что, когдаct
есть0
,val
будет заменено0
иct
будет заменено на1
.Аппроксимацию размера строки, включая содержимое TOAST , легко получить, запросив длину представления TEXT всей строки:
Это близкое приближение к количеству байтов, которые будут получены на стороне клиента при выполнении:
... при условии, что вызывающий запрос запрашивает результаты в текстовом формате, что и делают большинство программ (двоичный формат возможен, но в большинстве случаев это не стоит проблем).
Тот же метод может быть применен для определения местоположения самых
N
больших в тексте строкtablename
:источник
Есть несколько вещей, которые могут происходить. В общем, я сомневаюсь, что длина является проксимальной проблемой. Я подозреваю, что вместо этого у вас есть проблема, связанная с длиной.
Вы говорите, что текстовые поля могут достигать нескольких k. Строка не может превышать 8 КБ в основном хранилище, и вполне вероятно, что ваши большие текстовые поля были TOASTed или перемещены из основного хранилища в расширенное хранилище в отдельных файлах. Это делает ваше основное хранилище быстрее (так что select id на самом деле быстрее, потому что меньше страниц на диске для доступа), но select * становится медленнее, потому что больше случайных операций ввода-вывода.
Если ваш общий размер строки все еще не превышает 8 КБ, вы можете попробовать изменить настройки хранилища. Однако я хотел бы предупредить, что при вставке негабаритного атрибута в основное хранилище могут случиться плохие вещи, поэтому лучше не трогать это, если вам не нужно, и если вы это сделаете, установите соответствующие ограничения с помощью проверочных ограничений. Так что транспортировка вряд ли единственная вещь. Это может сопоставлять много, много полей, которые требуют случайного чтения. Большое количество случайных чтений может также привести к ошибкам в кеше, а большой объем требуемой памяти может потребовать материализации вещей на диске и большого количества широких строк, если присутствует объединение (и есть одно, если задействован TOAST), может потребоваться более дорогостоящее шаблоны соединения и т. д.
Первое, на что я хотел бы обратить внимание, это выбрать меньшее количество строк и посмотреть, поможет ли это. Если это сработает, вы также можете попытаться добавить больше оперативной памяти на сервер, но я бы начал с того, чтобы посмотреть, где начинает падать производительность из-за изменений в плане и отсутствия кэша.
источник
Использование функций размера объекта базы данных, упомянутых выше:
источник