слишком много параметров для raise
Слишком много параметров для raise
Команда RAISE предназначена для вывода сообщений и вызова ошибок.
В следующем примере символ % будет заменён на значение v_job_id :
При помощи USING и последующих элементов параметр = выражение можно добавить дополнительную информацию к отчёту об ошибке. Все выражения представляют собой строковые выражения. Возможные ключевые слова для параметра следующие:
Предоставляет детальное сообщение об ошибке. HINT
Предоставляет подсказку по вызванной ошибке. ERRCODE
Предоставляет имя соответствующего объекта, связанного с ошибкой.
Этот пример прерывает транзакцию и устанавливает сообщение об ошибке с подсказкой:
Следующие два примера демонстрируют эквивалентные способы задания SQLSTATE :
У команды RAISE есть и другой синтаксис, в котором в качестве главного аргумента используется имя или код SQLSTATE ошибки. Например:
Предложение USING в этом синтаксисе можно использовать для того, чтобы переопределить стандартное сообщение об ошибке, детальное сообщение, подсказку. Ещё один вариант предыдущего примера:
И заключительный вариант, в котором RAISE не имеет параметров вообще. Эта форма может использоваться только в секции EXCEPTION блока и предназначена для того, чтобы повторно вызвать ошибку, которая сейчас перехвачена и обрабатывается.
Примечание
Если в команде RAISE EXCEPTION не задано ни имя условия, ни код SQLSTATE, по умолчанию выдаётся исключение ERRCODE_RAISE_EXCEPTION ( P0001 ). Если не задан текст сообщения, по умолчанию в качестве этого текста передаётся имя условия или код SQLSTATE.
Примечание
40.8.2. Проверка утверждений
PostgreSQL RAISE EXCEPTION
By Priya Pedamkar
Introduction to PostgreSQL RAISE EXCEPTION
PostgreSQL raises an exception is used to raise the statement for reporting the warnings, errors and other type of reported message within a function or stored procedure. We are raising the exception in function and stored procedures in PostgreSQL; there are different level available of raise exception, i.e. info, notice, warning, debug, log and notice. We can basically use the raise exception statement to raise errors and report the messages; by default, the exception level is used in the raise exception. We can also add the parameter and variable in the raise exception statement; also, we can print our variable’s value.
Syntax:
Hadoop, Data Science, Statistics & others
Given below is the syntax:
RAISE [LEVEL] (Level which we have used with raise exception statement.) [FORMAT]
RAISE [ LEVEL] USING option (Raise statement using option) = expression
Parameters Description:
How RAISE EXCEPTION work in PostgreSQL?
We can raise the exception by violating the data integrity constraints in PostgreSQL. Raise exception is basically used to raise the error and report the messages.
Given below shows the raise statement-level options, which was specifying the error severity in PostgreSQL:
If we need to raise an error, we need to use the exception level after using the raise statement in it.
We can also add more detailed information about the error by using the following clause with the raise exception statement in it.
USING option = expression
We can also provide an error message that is used to find the root cause of the error easier, and it is possible to discover the error. The exception gives an error in the error code; we will identify the error using the error code; it will define either a SQL State code condition. When the raise statement does not specify the level, it will specify the printed message as an error. After printing, the error message currently running transaction is aborted, and the next raise statement is not executed.
It is used in various parameters or options to produce an error message that is more informative and readable. When we are not specifying any level, then by default, the exception level is used in the raise statement. The exception level is aborted the current transaction with a raise statement in it. The exception level is very useful and important to raise the statement to abort the current transaction in it.
Examples of PostgreSQL RAISE EXCEPTION
Given below are the examples mentioned:
Example #1
Raise an exception statement, which reports different messages.
Code:
Output:
In the above example, only info, warning, notice and exception will display the information. But debug and log will not display the output information.
Example #2
Raise error using raise exception.
Code:
Output:
Example #3
Raise exception by creating function.
Code:
create or replace function test_exp() returns void as
$$
begin
raise exception using message = ‘S 167’, detail = ‘D 167’, hint = ‘H 167’, errcode = ‘P3333’;
end;
$$ language plpgsql
;
Output:
Advantages of PostgreSQL RAISE EXCEPTION
Below are the advantages:
Conclusion
RAISE EXCEPTION in PostgreSQL is basically used to raise the warning and error message. It is very useful and important. There are six levels of raise exception is available in PostgreSQL, i.e. notice, log, debug, warning info and exception. It is used in various parameters.
Recommended Articles
This is a guide to PostgreSQL RAISE EXCEPTION. Here we discuss how to RAISE EXCEPTION work in PostgreSQL, its advantages and examples. You may also have a look at the following articles to learn more –
All in One Data Science Bundle (360+ Courses, 50+ projects)
How to raise errors and report messages within stored procedures and functions
SUMMARY: This article discusses the RAISE command for reporting errors, warnings, and other report messages within stored procedures and functions in PostgreSQL. Levels of error messages are covered along with settings for specifying their display to the client or log.
2. RAISE INFO/WARNING/NOTICE
5. USING option = expression
PL/pgSQL is one of the most popular procedural languages in PostgreSQL. It provides the capability of creating functions and procedures that help the user perform reusable complex computations. A typical procedure is created using different procedural constructs including block structures, variables, SQL commands, and error-handling.
In PostgreSQL, RAISE is used to report errors and messages. In this article, we will be focusing on how to use RAISE to implement error-handling within stored procedures and functions.
RAISE is used to raise errors and report messages, PostgreSQL provides various parameters to report an error, warning, and information at a detailed level. Below is the basic syntax for the RAISE command.
Syntax
Level indicates error severity. The level can be (in order from least to most severe) DEBUG, LOG, INFO, NOTICE, WARNING, or EXCEPTION. EXCEPTION is the default level and the only one that will halt the procedure. Each level generates an error message with detailed information based on priority levels.
Users can control where these error messages will be reported (i.e., on client screen, server logs or on both) by setting the postgresql.conf parameters “log_min_messages” and “client_min_messages.”
Format specifies the error message that the user wants to display. If the message needs some variable values to be printed with it, the “%” sign is used. The “%” sign acts as a placeholder and is replaced by the variable value given with the RAISE command. This can be used multiple times.
Let’s demonstrate all of this with an example:
In this example “RAISE NOTICE ‘value of a : %’, a;” is used to print “NOTICE: value of a : 10” when the procedure is called. The severity level of NOTICE is used to print the message “value of a” and “%” is replaced by the value of variable “a,” which is 10 in this instance.
RAISE INFO/WARNING/NOTICE
These are generally reported back to the client based on “client_min_messages” and “log_min_messages” settings. INFO, WARNING, and NOTICE can be used as named states to display warning information to the user.
RAISE LOG/DEBUG
The LOG and DEBUG levels are generally not reported back to the client under the default “client_min_messages” and “log_min_messages” settings.
As seen above the procedure is called and nothing is printed to the client. By default, LOG will output a message in the server log.
DEBUG will output to the client when “client_min_messages” is set to the DEBUG level.
RAISE EXCEPTION
When no level is specified, EXCEPTION is used by default. EXCEPTION will abort the current transaction.
As seen above, when the RAISE statement does not specify a level, the message is printed as an ERROR, and the transaction is aborted, so the next RAISE statement isn’t executed. The same output will be produced when “RAISE EXCEPTION ‘value of a : %’, a;” is used instead.
RAISE can be used with various options to make the error message more readable and informative by using below syntax.
USING option = expression
Options can be MESSAGE, DETAIL, HINT, ERRCODE, etc., and expression is a single value statement.
Along with the ERROR message this example also outputs a HINT property back to the client. In a similar way, MESSAGE, DETAIL, and ERRCODE can also be used.
PostgreSQL Antipatterns: обновляем большую таблицу под нагрузкой
Как стоит поступить (а как точно не надо), если в «многомиллионной» активно используемой таблице PostgreSQL нужно обновить большое количество записей — проинициализировать значение нового поля или скорректировать ошибки в существующих записях? А при этом сохранить свое время и не потерять деньги компании из-за простоя.
Подготовим тестовые данные:
Допустим, мы хотим просто увеличить значение v на 1 у всех записей с k в диапазоне ‘q’..’z’.
Но, прежде чем начать эксперименты, сохраним исходный датасет, чтобы иметь «чистые» результаты каждый раз:
UPDATE: один за всех, и все за одного
Самый простой вариант, который сразу приходит на ум — сделать все «за один UPDATE»:
[посмотреть на explain.tensor.ru]
Достаточно простая, казалось бы, операция на совсем «коротких» строках выполнялась дольше 2.5 секунд. А если выражение у вас будет посложнее, строка подлиннее, записей побольше, да еще и какие-нибудь триггеры вмешаются — время может увеличиться даже не до минут, а до часов. Положим, вы-то готовы подождать, а вся остальная ваша система, завязанная на эту базу, если в нее идет активная OLTP-нагрузка?
Проблема в том, что как только UPDATE добирается до конкретной записи, он ее блокирует до окончания выполнения. Если одновременно с той же записью захочет поработать параллельно запустившийся «точечный» UPDATE, он все равно «зацепится» на ожидании блокировки за обновляющий запрос, и провисит так до самого конца его работы.
© wumo.com/wumo
Хуже всего в такой ситуации приходится web-системам, где соединения к БД создаются по мере надобности — ведь такие «повисшие» коннекты накапливаются и будут проедать ресурсы как БД, так и клиента, если не делать от этого отдельный защитный механизм.
Дробим транзакции
В общем, все не очень хорошо, если все делать за один запрос. Да и даже если мы разделим один большой UPDATE на несколько маленьких, но оставим все это работать в одной транзакции — проблема с блокировкой останется та же самая, потому что изменяемые записи блокируются до окончания всей транзакции.
Значит, нам надо разбить одну большую транзакцию на несколько. Для этого мы можем или использовать внешние средства, и написать какой-то порождающий отдельные транзакции скрипт, или использовать те возможности, которые нам может предоставить сама база.
CALL и управление транзакциями
В процедурах, вызываемых командой CALL, а также в анонимных блоках кода (в команде DO) можно завершать транзакции, выполняя COMMIT и ROLLBACK. После завершения транзакции этими командами новая будет начата автоматически.
Но эта версия стоит «на бою» далеко не у всех, да и работа с CALL имеет свои ограничения. Поэтому попробуем решить нашу задачу без внешних средств, и так чтобы она работала на всех актуальных версиях, да еще и с минимальными изменениями на самом сервере — чтобы не надо было ничего компилировать и перезапускать.
По этой же причине не будем рассматривать и вариант организации автономных транзакций через pg_background.
Управление соединениями «внутри» базы
Для эмуляции автономных транзакций в PostgreSQL исторически используются разные методы, порождающие отдельные дополнительные соединения — через дополнительные процедурные языки или штатный модуль dblink. Преимущество последнего в том, что он по умолчанию входит в большинство дистрибутивов, и для его активации в базе требуется всего одна команда:
«… и много-много ргадостей детишкам принесла»
Но прежде чем создавать dblink-обвязку, давайте сначала прикинем, как «обычный разработчик» разбивает большой датасет, который ему надо обновить, на маленькие.
Наивный LIMIT… OFFSET
Первая же идея — сделать «постраничный» перебор: «Давайте будем отбирать каждый раз следующую тысячу записей» с помощью увеличения OFFSET в каждом новом запросе:
Прежде чем тестировать производительность этого решения, восстановим датасет:
Как мы видели в плане выше, обновиться у нас должны будут примерно 384K записей. Поэтому давайте сразу посмотрим, как будут выполняться обновления ближе к концу — в районе 300-й итерации по 1000 записей:
[посмотреть на explain.tensor.ru]
Ой… Обновление находящейся ближе к концу выборки всего 1K записей будет стоить нам практически столько же времени, как весь исходный вариант целиком!
Это не наш выбор. Он еще может как-то использоваться, если получается мало итераций и небольшие значения OFFSET. Потому что LIMIT X OFFSET Y для базы эквивалентно «вычитай/отбери/сформируй сначала X+Y записей, а потом первые Y выкинь в мусор«, что при больших значениях Y выглядит трагично.
На самом деле, такой способ вообще нельзя применять! Мало того, что мы опираемся при отборе на обновляемые значения, так еще и рискуем пропустить часть записей, а другую часть обновить дважды, если блоки с одинаковыми ключами попадут на границу страниц:
В этом примере «зеленую» запись мы обновили дважды, а «красную» — ни разу. Просто потому, что при одинаковых значениях ключей сортировки порядок самих записей внутри такого блока не фиксирован.
Печальный ORDER BY… LIMIT
Давайте чуть модифицируем задачу — добавим новое поле, в которое и будем записывать наше значение v + 1:
Обратите внимание, что такая конструкция работает практически мгновенно, без переписывания всей таблицы. А вот если добавить DEFAULT-значение, то — только начиная с 11-й версии.
Уже наученные горьким опытом, давайте сразу создадим индекс, в котором будут оставаться только неинициализированные записи:
CONCURRENTLY-индекс не блокирует работу с таблицей на чтение-запись, пока неспешно накатывается даже на огромный датасет.
Теперь идея звучит как «Давайте отбирать из этого индекса каждый раз только первую тысячу записей»:
[посмотреть на explain.tensor.ru]
Уже много лучше — длительность каждой отдельной транзакции теперь у нас короче примерно в 6 раз.
Но давайте опять посмотрим, во что превратится план к 200-й итерации:
Время опять ухудшилось (правда, всего на 25%), и значение buffers выросло — но почему?
Дело в том, что MVCC в PostgreSQL оставляет в индексе «мертвые души» — версии уже обновленных записей, теперь под индекс уже не подходящих. То есть отбирая всего 1000 первых записей на 200-й итерации, мы все равно сканируем, хоть потом и отбрасываем, предыдущие 199K уже измененных версий кортежей.
Если итераций у нас требуется не несколько сотен, а несколько сотен тысяч, то деградация будет все заметнее с каждым следующим выполнением запроса.
UPDATE по сегментам
Собственно, а чего мы так привязались к этому значению «1000 записей»? Ведь у нас нет причин выбирать ровно по 1000 или какому-то другому конкретному числу. Мы всего-то хотели просто весь датасет «нарезать» на какие-то, необязательно равные, непересекающиеся сегменты — так давайте используем по прямому назначению имеющийся у нас индекс.
Для нашей задачи индексированная пара (k, v) отлично подходит. Построим запрос, чтобы он мог отталкиваться от последней обработанной пары:
На первой итерации нам достаточно выставить параметры запроса в «нулевое» значение (», 0), а для каждой следующей итерации брать результат предыдущего запроса.
[посмотреть на explain.tensor.ru]
Время транзакции/блокировок — меньше миллисекунды, деградации от количества итераций — нет, полное предварительное сканирование всех данных в таблице — не требуется. Отлично!
Дополнительное преимущество такого способа заключается в возможности прервать выполнение этого скрипта в любой момент, а потом возобновить с нужной точки.
Сложные вычисления в UPDATE
Отдельно упомяну ситуацию со сложным вычислением присваиваемого значения — когда надо что-то посчитать по связаным таблицам.
Время, затрачиваемое на вычисления, точно так же увеличивает длительность транзакции. Поэтому наиболее оптимальным вариантом будет вынести процесс вычисления этих значений за рамки UPDATE.
Например, мы хотим заполнить наше новое поле x количеством записей, которые имеют то же значение (k,v). Создадим «временную» таблицу, генерация которой не накладывает дополнительных блокировок:
Теперь мы можем по описанной выше модели итерировать уже по этой таблице, обновляя целевую:
Как видим, никаких сложных вычислений уже не требуется.
Только не забудьте потом удалить вспомогательную таблицу.
Настройка параметров PostgreSQL для оптимизации производительности
По умолчанию конфигурация PostgreSQL не настроена для рабочей нагрузки. Значения по умолчанию установлены для обеспечения работоспособности PostgreSQL везде с наименьшим количеством ресурсов. Имеются настройки по умолчанию для всех параметров базы данных. Главной обязанностью администратора базы данных или разработчика является настройка PostgreSQL в соответствии с нагрузкой их системы. В этом блоге мы изложим основные рекомендации по настройке параметров базы данных PostgreSQL для повышения производительности базы данных в соответствии с рабочей нагрузкой.
Имейте в виду, что, хотя оптимизация конфигурации сервера PostgreSQL повышает производительность, разработчик базы данных также должен быть внимательным при написании запросов. Если запросы выполняют полное сканирование таблицы, где можно использовать индекс, или выполнют тяжелые объединения или дорогостоящие операции агрегирования, тогда система все равно может работать плохо, даже если параметры базы данных настроены корректно. При написании запросов к базе данных важно обращать внимание на производительность.
Тем не менее, параметры базы данных тоже очень важны, поэтому давайте посмотрим на восемь, которые имеют наибольший потенциал для повышения производительности
Настраиваемые параметры PostgreSQL
PostgreSQL использует свой собственный буфер, а также использует буферизованный IO ядра. Это означает, что данные хранятся в памяти дважды, сначала в буфере PostgreSQL, а затем в буфере ядра. В отличие от других баз данных, PostgreSQL не обеспечивает прямой ввод-вывод. Это называется двойной буферизацией. Буфер PostgreSQL называется shared_buffer, который является наиболее эффективным настраиваемым параметром для большинства операционных систем. Этот параметр устанавливает, сколько выделенной памяти будет использоваться PostgreSQL для кеширования.
Значение по умолчанию для shared_buffer установлено очень низким, и вы не получите большой выгоды от него. Сделано это потому, что некоторые машины и операционные системы не поддерживают более высокие значения. Но в большинстве современных машин вам необходимо увеличить это значение для оптимальной производительности.
Рекомендуемое значение составляет 25% от общего объема оперативной памяти компьютера. Вам следует попробовать некоторые более низкие и более высокие значения, потому что в некоторых случаях можно получить хорошую производительность с настройкой более 25%. Но реальная конфигурация зависит от вашей машины и рабочего набора данных. Если ваш рабочий набор данных может легко поместиться в вашу оперативную память, вы можете увеличить значение shared_buffer, чтобы оно содержало всю вашу базу данных и чтобы весь рабочий набор данных мог находиться в кеше. Тем не менее, вы, очевидно, не хотите резервировать всю оперативную память для PostgreSQL.
Замечено, что в производственных средах большое значение для shared_buffer действительно дает хорошую производительность, хотя для достижения правильного баланса всегда следует проводить тесты.
Проверка значения shared_buffer
Примечание: Будьте осторожны, так как некоторые ядра не поддерживают большее значение, особенно в Windows.
wal_buffers
PostgreSQL сначала записывает записи в WAL (журнал предзаписи) в буферы, а затем эти буферы сбрасываются на диск. Размер буфера по умолчанию, определенный wal_buffers, составляет 16 МБ. Но если у вас много одновременных подключений, то более высокое значение может повысить производительность.
effective_cache_size
effective_cache_size предоставляет оценку памяти, доступной для кэширования диска. Это всего лишь ориентир, а не точный объем выделенной памяти или кеша. Он не выделяет фактическую память, но сообщает оптимизатору объем кеша, доступный в ядре. Если значение этого параметра установлено слишком низким, планировщик запросов может принять решение не использовать некоторые индексы, даже если они будут полезны. Поэтому установка большого значения всегда имеет смысл.
work_mem
Эта настройка используется для сложной сортировки. Если вам нужно выполнить сложную сортировку, увеличьте значение work_mem для получения хороших результатов. Сортировка в памяти происходит намного быстрее, чем сортировка данных на диске. Установка очень высокого значения может стать причиной узкого места в памяти для вашей среды, поскольку этот параметр относится к операции сортировки пользователя. Поэтому, если у вас много пользователей, пытающихся выполнить операции сортировки, тогда система выделит:
для всех пользователей. Установка этого параметра глобально может привести к очень высокому использованию памяти. Поэтому настоятельно рекомендуется изменить его на уровне сеанса.
Первоначальный узел сортировки запроса оценивается в 514431,86. Стоимость — это произвольная вычисляемая единица. Для приведенного выше запроса у нас work_mem всего 2 МБ. В целях тестирования давайте увеличим это значение до 256 МБ и посмотрим, повлияет ли это на стоимость.
Стоимость запроса снижена с 514431,86 до 360617,36, то есть уменьшилась на 30%.
maintenance_work_mem
maintenance_work_mem — это параметр памяти, используемый для задач обслуживания. Значение по умолчанию составляет 64 МБ. Установка большого значения помогает в таких задачах, как VACUUM, RESTORE, CREATE INDEX, ADD FOREIGN KEY и ALTER TABLE.
Время создания индекса составляет 170091,371 мс, если для параметра maintenance_work_mem установлено значение только 10 МБ, но оно уменьшается до 111274,903 мс, когда мы увеличиваем значение параметра maintenance_work_mem до 256 МБ.
synchronous_commit
Используется для обеспечения того, что фиксация транзакции будет ожидать записи WAL на диск, прежде чем вернуть клиенту статус успешного завершения. Это компромисс между производительностью и надежностью. Если ваше приложение разработано таким образом, что производительность важнее надежности, отключите synchronous_commit. В этом случае транзакция фиксируется очень быстро, потому что она не будет ожидать сброса файла WAL, но надежность будет поставлена под угрозу. В случае сбоя сервера данные могут быть потеряны, даже если клиент получил сообщение об успешном завершении фиксации транзакции.
checkpoint_timeout, checkpoint_completion_target
PostgreSQL записывает изменения в WAL. Процесс контрольной точки сбрасывает данные в файлы. Это действие выполняется, когда возникает контрольная точка (CHECKPOINT). Это дорогостоящая операция и может вызвать огромное количество операций IO. Весь этот процесс включает в себя дорогостоящие операции чтения/записи на диск. Пользователи могут всегда запустить задание контрольной точки (CHECKPOINT), когда это необходимо, или автоматизировать запуск с помощью параметров checkpoint_timeout и checkpoint_completion_target.
Параметр checkpoint_timeout используется для установки времени между контрольными точками WAL. Установка слишком низкого значения уменьшает время восстановления после сбоя, поскольку на диск записывается больше данных, но это также снижает производительность, поскольку каждая контрольная точка в конечном итоге потребляет ценные системные ресурсы.
checkpoint_completion_target — это доля времени между контрольными точками для завершения контрольной точки. Высокая частота контрольных точек может повлиять на производительность. Для плавного выполнения задания контрольной точки, checkpoint_timeout должен иметь низкое значение. В противном случае ОС будет накапливать все грязные страницы до тех пор, пока соотношение не будет соблюдено, а затем производить большой сброс.