У каждого из нас есть задача, над которой вы долго и безуспешно бьетесь, которую уже изучили вдоль и поперёк, но до сих пор не можете получить желаемый результат. При этом одни уверены, что ваша проблема в принципе не имеет решения, другие – что проблемы вообще нет. Для меня этой проблемой было время, необходимое для выполнения запросов к хранилищу данных Greenplum. И как приятно наконец написать, что я поборола эту проблему!
Когда пытаешься понять, почему запросы выполняются так долго Раз за разом при работе с репозиторием ожидание результата запроса занимало несколько минут. И не важно, будет ли запрос выбирать данные из таблицы на десять строк или на миллион — время ожидания будет сопоставимым.
А любой простой в таком творческом процессе, как аналитика, – это просто пытка! Я много раз пытался исправить это поведение.
Я начал с настройки клиента sql. DBeaver предлагает пользователям целый ряд различных вариантов тонкой настройки — думаю, я опробовал их все безуспешно.
Далее я попробовал настройки самого драйвера PostgreSQL — эффект был тот же.
Все это время перед моими глазами был пример специализированного клиента для Greenplum — Aginity Workbench, в котором из коробки скорость выполнения подобных запросов существенно выше.
Эта программа была дополнительным раздражающим фактором, так как причин такого ускорения я найти не смог - ее исходный код закрыт и она работает только под лицензией, а подключение к greenplum в ней происходит родными средствами, а не штатными jdbc-драйверами.
.
Вдохновение пришло, когда я заглянул в системное представление pg_ стат_ активности — оказалось, что на самом деле от клиента в базу данных летит не один запрос данных, а два: сначала происходит выборка данных по запросу, а затем метаданные для этой выборки считываются из pg_ каталог.
При этом из общего времени выполнения наибольшую часть занимает чтение метаданных.
В этот момент я испытал целую бурю эмоций – от радости, что наконец-то нашел проблему, до недоумения по поводу самой сути открытия.
Я и раньше знал, что каталог изрядно загружен: сейчас к хранилищу подключено более 250 исходных систем, каждая с сотней таблиц, а сами таблицы могут иметь двухуровневую партиционацию.
Greenplum рассматривает каждый раздел как отдельный объект, поэтому системные представления, такие как pg_class, становятся сильно раздутыми.
Но действительно ли необходим доступ к каталогу для любого запроса данных? К счастью, драйвер Postgres имеет открытый исходный код. источник , чтобы вы могли сами увидеть, что происходит под капотом.
Я заглянул в код и нашел нужный класс.
Пгрезультатсетметадата и его метод, запрашивающий метаданные, — fetchFieldMetaData. Содержание обнадёживает - вроде можно обойтись и без метаданных: fetchFieldMetaData вызывается из нескольких других методов, которые для моих целей не столь важны, а сами эти методы позволяют вернуть пустой объект, что намекает на возможность вырезания исключить все вызовы fetchFieldMetaData из кода, что означает отсутствие медленных запросов к каталогу.
Подробнее о методах:
- isAutoIncrement. В этом методе проще всего избегать запроса метаданных: в нашем репозитории таких полей нет, а комментарий «Считается, что PostgreSQL не поддерживает эту возможность» как бы намекает, что для других баз данных она не будет полезна.
public boolean isAutoIncrement(int column) throws SQLException { fetchFieldMetaData(); Field field = getField(column); FieldMetadata metadata = field.getMetadata(); return metadata != null && metadata.autoIncrement; }
- isNullable. Если в наборе результатов нет метаданных, все поля будут считаться обнуляемыми — без больших потерь.
public int isNullable(int column) throws SQLException { fetchFieldMetaData(); Field field = getField(column); FieldMetadata metadata = field.getMetadata(); return metadata == null ? ResultSetMetaData.columnNullable : metadata.nullable; }
- getBaseColumnName. В коде драйвера этот метод используется в обновляемых наборах результатов при обновлении значений.
В мои планы не входит использование этого функционала, но на всякий случай можно будет добавить исключения при вызове таких методов.
public String getBaseColumnName(int column) throws SQLException { Field field = getField(column); if (field.getTableOid() == 0) { return ""; } fetchFieldMetaData(); FieldMetadata metadata = field.getMetadata(); return metadata == null ? "" : metadata.columnName; }
- getBaseSchemaName и getBaseTableName. Возвращает имя схемы/таблицы, в которой находится запрошенный атрибут. Этот метод нигде в коде драйвера не используется; Мне эта информация тоже не особо нужна.
public String getBaseSchemaName(int column) throws SQLException { fetchFieldMetaData(); Field field = getField(column); FieldMetadata metadata = field.getMetadata(); return metadata == null ? "" : metadata.schemaName; } public String getBaseTableName(int column) throws SQLException { fetchFieldMetaData(); Field field = getField(column); FieldMetadata metadata = field.getMetadata(); return metadata == null ? "" : metadata.tableName; }
Сказать, что это дало результат, значит ничего не сказать.
Запросы сейчас просто летят. Ускорение - во много раз.
Отправил коллегам на пробу — отзывы были примерно такие:
Дополнительный бонус, который греет сердце: исключив ненужные запросы метаданных к каталогу pgclass, мы снимаем с него лишнюю нагрузку.
Не уверен, что это имеет какой-то существенный эффект для хранилища, но здесь, как и в борьбе за экологию, даже отрадно, что вы хоть несколько улучшаете ситуацию.
В общем, не опускайте руки, если проблема сохраняется долгое время – вполне вероятно, что ответ где-то рядом и какая-то мелочь отделяет вас от успеха.
В моем случае такой мелочью были символы комментариев, которые нужно было разместить в нужных местах.
P.S. В финальной версии кода я создал новый параметр подключения драйвера runtimeMetaDisable. Вызов метаданных и выдача исключений привязаны к их значению.
Такой подход более гибок, чем строго комментируемый вызов метода, и позволяет управлять поведением драйвера в зависимости от ваших потребностей.
Код был опубликован на github .
Если ваша база данных имеет тяжёлый каталог и вы хотите попробовать драйвер в действии, но не знакомы с миром java и не знаете, как собрать jar-файл драйвера, пишите в комментариях! Теги: #greenplum #postgres #sql #управление данными в ростелекоме #Jdbc #driver
-
Основы Драйверов Устройств
19 Oct, 24 -
Хакатон №1 На Тинькофф.ру
19 Oct, 24 -
Ubuntu Для Нетбуков: Версия Hp
19 Oct, 24 -
Js2Js: Компилятор Javascript В Javascript.
19 Oct, 24