powered by simpleCommunicator - 2.0.49     © 2025 Programmizd 02
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Ошибка при создании секционированной таблицы в постгресе
22 сообщений из 22, страница 1 из 1
Ошибка при создании секционированной таблицы в постгресе
    #39940324
kirill demidov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Всем привет!

Я строю динамическое секционирование таблицы по метке времени с интервалом в час и у меня не получается писать в новую таблицу.

Родительская таблица:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
CREATE TABLE dwh.fact_measures_raw (
	id serial NOT NULL,
	equipment_id varchar NULL,
	parameter_id varchar NULL,
	value float8 NULL,
	ts_original int8 NULL,
	ts_timestamp timestamp NULL,
	created_at timestamp NULL DEFAULT now(),
	updated_at timestamp NULL DEFAULT now()
);
CREATE INDEX idx_ts_timestamp ON dwh.fact_measures_raw USING btree (ts_timestamp);



Текст функции, которая создает динамически новые секционные таблицы, и текст триггера перед INSERT:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
CREATE OR REPLACE FUNCTION dwh.fact_raw_insert_function()
 RETURNS trigger
 LANGUAGE plpgsql
AS $function$
declare
	partition_date text;

partition_name text;

start_of_hour text;

end_of_next_hour text;


begin partition_date := to_char(NEW.ts_timestamp, 'YYYY-MM-DD-HH');

partition_name := 'dwh.raw_data_' || partition_date;

start_of_hour := to_char((NEW.ts_timestamp), 'YYYY-MM-DD HH:DD:SS') || '-01';

end_of_next_hour := to_char((NEW.ts_timestamp + interval '1 hour'), 'YYYY-MM-DD HH:DD:SS') || '-01';

if not exists (
select
	1
from
	information_schema.tables
where
	table_name = partition_name) then raise notice 'A partition has been created %',
partition_name;

execute format(E'CREATE TABLE %I (CHECK ( date_trunc(\'hour\', ts_timestamp) >= ''%s'' AND date_trunc(\'hour\', ts_timestamp) < ''%s'')) 
INHERITS (dwh.fact_measures_raw)',
partition_name,
start_of_hour,
end_of_next_hour);


 end if;

execute format('INSERT INTO %I (equipment_id,parameter_id,value,ts_original,ts_timestamp) VALUES($1,$2,$3,$4,$5)',
partition_name)
	using NEW.equipment_id,new.parameter_id,new.value,new.ts_original,NEW.ts_timestamp;

return null;

end $function$;

CREATE TRIGGER fact_raw_insert
    BEFORE INSERT ON dwh.fact_measures_raw
    FOR EACH ROW EXECUTE PROCEDURE dwh.fact_raw_insert_function();




При выполнении записи новых строк я получаю вот такую ошибку и уже голову сломал в чем проблема:


SQL Error [23514]: ERROR: new row for relation "dwh.raw_data_2020-03-23-04" violates check constraint "dwh.raw_data_2020-03-23-04_ts_timestamp_check"
Detail: Failing row contains (1218483, 4161341a-ad79-4021-b6fa-f6754f34f5cb, frequency, 49.8486557006835938, 1584974047062000, 2020-03-23 16:34:07, 2020-03-23 16:54:30.598366, 2020-03-23 16:54:30.598366).
Where: SQL statement "INSERT INTO "dwh.raw_data_2020-03-23-04" (equipment_id,parameter_id,value,ts_original,ts_timestamp) VALUES($1,$2,$3,$4,$5)"
PL/pgSQL function dwh.fact_raw_insert_function() line 38 at EXECUTE
SQL statement "insert into dwh.fact_measures_raw (equipment_id,
parameter_id,
value,
ts_original,
ts_timestamp)
select id, column_name, cast(column_value as float8),cast(ts as bigint),
to_timestamp( NULLIF(ts, '')::bigint/1000000)
from dwh.vw_stg_raw
where column_value is not null
and column_name not in ('ts','created_at')
and created_at < date_insert"
PL/pgSQL function dwh.insert_fact_measures_raw() line 6 at SQL statement


Что я делаю не так?

Спасибо!
...
Рейтинг: 0 / 0
Ошибка при создании секционированной таблицы в постгресе
    #39940350
Melkij
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kirill demidov,

CHECK ( date_trunc(\'hour\', ts_timestamp)
где ts_timestamp = 2020-03-23 16:34:07
но new row for relation "dwh.raw_data_2020-03-23-04"
Почему? Странная разница в 12 часов не побуждает проверить вполне определённую штуку?

https://www.postgresql.org/docs/current/functions-formatting.html
HH hour of day (01-12)

А вообще не надо создавать партиции из триггера.
...
Рейтинг: 0 / 0
Ошибка при создании секционированной таблицы в постгресе
    #39940422
kirill demidov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Melkij,

Спасибо за замечание!

А как бы вы создавали динамические секции?
...
Рейтинг: 0 / 0
Ошибка при создании секционированной таблицы в постгресе
    #39940435
kirill demidov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Melkij
kirill demidov,

CHECK ( date_trunc(\'hour\', ts_timestamp)
где ts_timestamp = 2020-03-23 16:34:07
но new row for relation "dwh.raw_data_2020-03-23-04"
Почему? Странная разница в 12 часов не побуждает проверить вполне определённую штуку?

https://www.postgresql.org/docs/current/functions-formatting.html
HH hour of day (01-12)


А вообще не надо создавать партиции из триггера.


Я изменил функцию:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
begin partition_date := to_char(NEW.ts_timestamp, 'YYYY-MM-DD-HH24');

partition_name := 'dwh.raw_data_' || partition_date;

start_of_hour := to_char((NEW.ts_timestamp), 'YYYY-MM-DD HH24:DD:SS') || '-01';

end_of_next_hour := to_char((NEW.ts_timestamp + interval '1 hour'), 'YYYY-MM-DD HH24:DD:SS') || '-01';



но продолжаю получать ту же ошибку:


SQL Error [23514]: ERROR: new row for relation "dwh.raw_data_2020-03-24-07" violates check constraint "dwh.raw_data_2020-03-24-07_ts_timestamp_check"
Detail: Failing row contains (25631259, 4161341a-ad79-4021-b6fa-f6754f34f5cb, frequency, 50.6228485107421875, 1585026909342000, 2020-03-24 07:15:09, 2020-03-24 07:15:21.33603, 2020-03-24 07:15:21.33603).
Where: SQL statement "INSERT INTO "dwh.raw_data_2020-03-24-07" (equipment_id,parameter_id,value,ts_original,ts_timestamp) VALUES($1,$2,$3,$4,$5)"
PL/pgSQL function dwh.fact_raw_insert_function() line 38 at EXECUTE
SQL statement "insert into dwh.fact_measures_raw (equipment_id,
parameter_id,
value,
ts_original,
ts_timestamp)
select id, column_name, cast(column_value as float8),cast(ts as bigint),
to_timestamp( NULLIF(ts, '')::bigint/1000000)
from dwh.vw_stg_raw
where column_value is not null
and column_name not in ('ts','created_at')
and created_at < date_insert"
PL/pgSQL function dwh.insert_fact_measures_raw() line 6 at SQL statement


Может у меня еще где-то есть проблема?
У меня такое ощущение что проблема в части создания новой таблицы-секции, но я не понимаю, блин, как это дебагнуть. Я просто пришел из мира SQL Server и только начинаю свои первые шаги в постгресе...
...
Рейтинг: 0 / 0
Ошибка при создании секционированной таблицы в постгресе
    #39940465
Melkij
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kirill demidov
А как бы вы создавали динамические секции?

Никак.
Какие разделы нужны известно заранее.

kirill demidov
start_of_hour := to_char((NEW.ts_timestamp), 'YYYY-MM-DD HH24:DD:SS') || '-01';

И что же тут может пойти не так...
Посмотрите какой check constraint создали и почему оно violates для заданного timestamp. Опять же весьма очевидно.
...
Рейтинг: 0 / 0
Ошибка при создании секционированной таблицы в постгресе
    #39940474
Павел Лузанов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kirill demidov,

Посмотрите на timescaledb .
То что вам нужно оно умеет делать.
Хотя в долгосрочной перспективе у меня есть сомнения.
...
Рейтинг: 0 / 0
Ошибка при создании секционированной таблицы в постгресе
    #39940486
kirill demidov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Melkij,

Заранее почасовые секции для таблицы с более чем миллионом транзакций в час на ближайший год сделать проблематично - "Это же так очевидно!"

У таблицы нет одного констрейнта - я ведь показал скрипт создания таблицы - других объектов нет.
...
Рейтинг: 0 / 0
Ошибка при создании секционированной таблицы в постгресе
    #39940490
Melkij
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kirill demidov
Melkij,

Заранее почасовые секции для таблицы с более чем миллионом транзакций в час на ближайший год сделать проблематично - "Это же так очевидно!"

Миллион в час - это не много.
Тысячи партиций - это много. Слишком много для OLTP.

Для партиций по времени создания у вас есть знание куда новые данные будут писаться и когда. Кроном их создают немного загодя, чтобы иметь время на манёвры.

kirill demidov
У таблицы нет одного констрейнта - я ведь показал скрипт создания таблицы - других объектов нет.

CREATE TABLE %I (CHECK ( - вы писали?
Вот таблица. На ней constraint. Почему это вдруг "нет одного констрейнта" когда он есть?
...
Рейтинг: 0 / 0
Ошибка при создании секционированной таблицы в постгресе
    #39940614
kirill demidov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Melkij,
спасибо - буду проверять где проблема в процедуре и почему не работает инсерт
...
Рейтинг: 0 / 0
Ошибка при создании секционированной таблицы в постгресе
    #39941127
kirill demidov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Поменял весь концепт секционирования!

Благодаря совету Melkij, ушел от принципа триггеров и наследования и использую функцию Partition By в момент создания таблицы

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
CREATE TABLE dwh.fact_measures_raw (
	id serial NOT NULL,
	equipment_id varchar NULL,
	parameter_id varchar NULL,
	value float8 NULL,
	ts_original int8 NULL,
	ts_timestamp timestamp NULL,
	created_at timestamp NULL DEFAULT now(),
	updated_at timestamp NULL DEFAULT now()
) partition by range (ts_timestamp);


и динамическое создание секций еженедельно (кронтаб )с помощью процедуры:
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
CREATE OR REPLACE PROCEDURE dwh.fact_raw_measures_partitions()
 LANGUAGE plpgsql
AS $procedure$
declare
	partition_date text;
	partition_name text;
	start_date text;
	end_date text;
	i int;
	tble_name text;
	indx_name text;
begin
	i :=0;
	
	loop 
		exit when i>6 ;
		i:=i+1;
		
		partition_date := to_char((current_timestamp +  (i || ' day')::interval), 'YYYY_MM_DD');
		partition_name :=  'dwh.fact_measures_raw_' || partition_date;
		start_date := to_char((current_timestamp+ (i || ' day')::interval), 'YYYY-MM-DD');
		end_date := to_char((current_timestamp+ (i+1 || ' day')::interval), 'YYYY-MM-DD');
		tble_name = 'fact_measures_raw_'|| partition_date;
		indx_name = 'idx_ts_timestamp' || partition_date;

		if not exists (select 1 from information_schema.tables where table_name= tble_name ) then
		EXECUTE format('CREATE TABLE %s partition of dwh.fact_measures_raw for values from (%L) to (%L)',
				partition_name, start_date, end_date);
		execute format('CREATE INDEX %s ON %s USING btree (ts_timestamp);',indx_name,partition_name);

		end if;

	end loop ;
end;
$procedure$
;



Melkij спасибо за совет!

Тему можно закрывать
...
Рейтинг: 0 / 0
Ошибка при создании секционированной таблицы в постгресе
    #39951048
MacArrow
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Уважаемые, доброго времени суток!
Помогите старому ораклисту, у которого кривая судьбы завернула в сторону PG, понять, что не так синтаксисом!

Пытаюсь создать секционированную таблицу, сделал всё по доке (вроде бы), более того, используемый инструмент сгенерил тот же самый скрипт что и написал сам:

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
CREATE TABLE dm_schema.test_create_section_table (
	col_serial serial NOT NULL,
	col_ineger integer NOT NULL,
	col_varchar varchar(10) NULL,
	col_numeric numeric NULL,
	col_timestamp timestamp NULL,
	col_date date NOT NULL
)
PARTITION BY range (col_date)
TABLESPACE tabsp_data
;



Выдаёт ошибку:
Код: sql
1.
ERROR: cannot specify default tablespace for partitioned relations



Подскажите, что не так? Перелопатил Гугл, что-нибудь вразумительного не нашёл...
Версия 12.2
...
Рейтинг: 0 / 0
Ошибка при создании секционированной таблицы в постгресе
    #39951058
Melkij
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MacArrow,

голова партицированной таблицы не может указывать tablespace. tablespace могут быть определены для разделов с данными.
...
Рейтинг: 0 / 0
Ошибка при создании секционированной таблицы в постгресе
    #39951077
MacArrow
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Melkij
MacArrow,

голова партицированной таблицы не может указывать tablespace. tablespace могут быть определены для разделов с данными.


О! Спасибо! Отработало!
Где-то в Гугле вычитал, что наоборот, нужно явное указание ТС... Вот и купился!
...
Рейтинг: 0 / 0
Ошибка при создании секционированной таблицы в постгресе
    #39952125
MacArrow
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Melkij,

потребовалось другое решение... но возникли трудности с реализацией.
Подскажите пожалуйста, как обойти ошибку? Или же как это правильно реализовать в PG?
Версия 12.2

Таблица с секциями по методу "список" и по полю типа "дата":
Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
CREATE TABLE dm_schema.test_create_section_table (
	col_serial serial NOT NULL,
	col_ineger integer NOT NULL,
	col_varchar varchar(10) NULL,
	col_numeric numeric NULL,
	col_timestamp timestamp NULL,
	col_date date NULL,
	od_dt date NOT NULL
)
PARTITION BY LIST (od_dt);


Но при создании секции выдаёт ошибку:
Код: plsql
1.
CREATE TABLE dm_schema.test_create_section_table_2020_04_02 partition of test_create_section_table for values in ('od_dt');


Ошибка:
Код: plaintext
ERROR: invalid input syntax for type date: "od_dt"

В общем, вопрос: как избавиться/обойти?
...
Рейтинг: 0 / 0
Ошибка при создании секционированной таблицы в постгресе
    #39952142
Melkij
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MacArrow,

а что вы сделать хотите? Показанный partition разумеется некорректный.
...
Рейтинг: 0 / 0
Ошибка при создании секционированной таблицы в постгресе
    #39952235
MacArrow
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Melkij,

Да, разумеется... И решение тут "стандартное" - для "списка" в худшем случае должен быть тип "текст" (видимо). А если хотим по дате секционировать, то решение только через "диапазон" (но к сожалению, при "дате" диапазон не может быть в 1 день).

Всё верно я интерпретирую? И обходов никаких не может быть?
...
Рейтинг: 0 / 0
Ошибка при создании секционированной таблицы в постгресе
    #39952259
Melkij
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MacArrow
И решение тут "стандартное" - для "списка" в худшем случае должен быть тип "текст" (видимо).

Чего вдруг? Ошибку вы получаете именно потому что указанная строка 'od_dt' не есть дата. Укажите литерал даты.

MacArrow
но к сожалению, при "дате" диапазон не может быть в 1 день

Отчего же? range partition подразумевает условие from >= value < to
...
Рейтинг: 0 / 0
Ошибка при создании секционированной таблицы в постгресе
    #39952268
MacArrow
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Melkij,

Спасибо Вам за терпение и вразумительные ответы.

MelkijОтчего же? range partition подразумевает условие from >= value < to

При создании секции (условно: " from '01.01.2020' to '01.01.2020'"), выдало ошибку, что не может быть диапазон с одинаковыми границами... ЧЯДНТ?
...
Рейтинг: 0 / 0
Ошибка при создании секционированной таблицы в постгресе
    #39952274
Lonepsycho
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MacArrow
Melkij,

Спасибо Вам за терпение и вразумительные ответы.

MelkijОтчего же? range partition подразумевает условие from >= value < to


При создании секции (условно: " from '01.01.2020' to '01.01.2020'"), выдало ошибку, что не может быть диапазон с одинаковыми границами... ЧЯДНТ?

не читаете то что вам Melkij написал

MelkijОтчего же? range partition подразумевает условие from >= value < to
...
Рейтинг: 0 / 0
Ошибка при создании секционированной таблицы в постгресе
    #39952276
MacArrow
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Lonepsycho,

А по существу?
Это как раз был его ответ на мой вопрос о том, что нельзя создать диапазон в 1 день (в условном примере).
...
Рейтинг: 0 / 0
Ошибка при создании секционированной таблицы в постгресе
    #39952281
Melkij
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
for values from '01.01.2020' to '01.01.2020' означает условие:

'01.01.2020' >= value and value < '01.01.2020' and value is not null

Что в принципе невозможно ни для какого значения. Всегда пустая таблица.

Партиция для данных первого января записывается как for values from ('2020-01-01') to ('2020-01-02'). До второго января, не включая его.
...
Рейтинг: 0 / 0
Ошибка при создании секционированной таблицы в постгресе
    #39952287
MacArrow
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Melkij,

Огромнейшее спасибо!
...
Рейтинг: 0 / 0
22 сообщений из 22, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Ошибка при создании секционированной таблицы в постгресе
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]