powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Использование record в CHECK constarint
25 сообщений из 42, страница 1 из 2
Использование record в CHECK constarint
    #38556097
sp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Мне нужно при вставке для секционированной таблицы проверять соответствует ли запись определенным критериям - для этого я создал функцию в которой в качестве входного параметра является record.

У меня возникает вопрос - как передать текущую запись в данную функцию в выражении CHECK?
...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38556128
sp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
или таки использование функций в выражении CHECK для секционированных таблиц - это плохо?
Но тогда как разбивать по различным полям, к примеру:
- хочется секционировать по номерам документов что бы все документы с номерами, начинающимися с 1 попадали в одну секцию, начинающиеся с 2 - в другую и т.д.

ну и куча других примеров найдется
...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38556156
Фотография SmeL_md
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
секционированние
это что Partitioning (патрицирование) ? если да то check на каждую таблицу + триггер BEFORE INSERT в котором и определяем в какую таблицу писать данные
...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38556160
sp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SmeL_md,

с триггерами проблем нет - есть вопрос по CHECK
...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38556173
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
spSmeL_md,

с триггерами проблем нет - есть вопрос по CHECKвы можете передать туда рекорд как ROW-конструктор (см RTFM) (попросту -- перечислением всех полей записи в скобках. можно даже с полседующим кастом к типу).


Код: plsql
1.
F( (a,b,c,d)::mytable )



хотя, вас наверное интересует, как его передать не перечисляя поля [:0]
...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38556184
sp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qwwq,

да, вы правильно поняли - надо чтоб запись целиком без перечисления полей, но данный вопрос наверно отходит на другой план - по такому CHECK движок не сможет строить эффективные планы т.к. результат функции заранее не известен...
...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38556690
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
spМне нужно при вставке для секционированной таблицы проверять соответствует ли запись определенным критериям - для этого я создал функцию в которой в качестве входного параметра является record.

У меня возникает вопрос - как передать текущую запись в данную функцию в выражении CHECK?
Код: sql
1.
2.
ОШИБКА: функции PL/pgSQL не могут принимать тип record
SQL-состояние: 0A000


колитесь, что вы там передаёте
...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38556695
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
CREATE OR REPLACE FUNCTION f_test_reord(f test)
  RETURNS boolean AS
$BODY$BEGIN
	RETURN FALSE;
END;$BODY$
  LANGUAGE plpgsql immutable
  COST 100;
-----------------------
ALTER TABLE test
  ADD CHECK (f_test_reord(test));
------------------------
INSERT INTO test VALUE (7, sadasdasdaasdasdasdas);
---------------------------
ОШИБКА: новая строка в отношении "test" нарушает ограничение-проверку "test_check"
SQL-состояние: 23514
Подробности: Ошибочная строка содержит (7, sadasdasdaasdasdasdas).


ЗЫ
Код: sql
1.
2.
3.
--вариант ddl, отображаемый пж-одмином
ALTER TABLE test
  ADD CONSTRAINT test_check CHECK (f_test_reord(test.*));




PS если ф-я иммутабл - можете строить индекс.
(и для выделения партиции при планировании тоже может сгодиться, если в where будет та же ф-я.)
...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38556766
sp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qwwq,

спасибо большое!
...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38556777
sp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
возникла очередная проблема с секционированием:
имеем текстовое поле ContractNo. по нему настроено секционирование и проверка в секциях выглядит так
Код: plsql
1.
2.
3.
4.
partition1 -  CHECK ( ContractNo::int <= 100 )
partition2 -  CHECK ( ContractNo::int <= 200 )
...
partitionN -  CHECK ( ContractNo::int <= N*100 )



вставил случайные данные в разные секции от 1 до 500
Пытаюсь делать выборку

Код: plsql
1.
2.
set constraint_exclusion = on;
select * from documents where ContractNo::int > 100 and ContractNo::int < 300



в плане вижу что идет сканирование всех секций вместо 1й, 2й и 3й

Почему мой where не использует constraint_exclusion?
...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38556827
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
spвозникла очередная проблема с секционированием:
имеем текстовое поле ContractNo. по нему настроено секционирование и проверка в секциях выглядит так
Код: plsql
1.
2.
3.
4.
partition1 -  CHECK ( ContractNo::int <= 100 AND  ContractNo::int > 0 )
partition2 -  CHECK ( ContractNo::int <= 200  AND  ContractNo::int >100 )
...
partitionN -  CHECK ( ContractNo::int <= N*100  AND ContractNo::int > 100*(N-1) )



вставил случайные данные в разные секции от 1 до 500
Пытаюсь делать выборку

Код: plsql
1.
2.
set constraint_exclusion = on;
select * from documents where ContractNo::int > 100 and ContractNo::int < 300



в плане вижу что идет сканирование всех секций вместо 1й, 2й и 3й

Почему мой where не использует constraint_exclusion?
а вы дайте ему эту возможность, тогда и спрашивайте
...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38556872
sp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qwwq,

по вашему настоянию - дал :)
но результат прежний (
...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38556891
sp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: 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.
Subquery Scan on documents  (cost=1.55..149.56 rows=2 width=72) (actual time=0.057..0.067 rows=3 loops=1)
  Output: documents.id, documents.no
  Filter: (((documents.no)::integer > 100) AND ((documents.no)::integer < 300))
  Rows Removed by Filter: 7
  Buffers: shared hit=7
        Buffers: shared hit=7
        ->  Append  (cost=0.00..109.00 rows=5801 width=40) (actual time=0.006..0.013 rows=10 loops=1)
              Buffers: shared hit=6
              ->  Seq Scan on public.documents  (cost=0.00..1.00 rows=1 width=40) (actual time=0.004..0.004 rows=0 loops=1)
                    Output: documents.id, documents.no
                    Buffers: shared hit=1
              ->  Seq Scan on public.documents_1  (cost=0.00..21.60 rows=1160 width=40) (actual time=0.001..0.002 rows=5 loops=1)
                    Output: documents_1.id, documents_1.no
                    Buffers: shared hit=1
              ->  Seq Scan on public.documents_2  (cost=0.00..21.60 rows=1160 width=40) (actual time=0.001..0.001 rows=2 loops=1)
                    Output: documents_2.id, documents_2.no
                    Buffers: shared hit=1
              ->  Seq Scan on public.documents_3  (cost=0.00..21.60 rows=1160 width=40) (actual time=0.001..0.001 rows=1 loops=1)
                    Output: documents_3.id, documents_3.no
                    Buffers: shared hit=1
              ->  Seq Scan on public.documents_4  (cost=0.00..21.60 rows=1160 width=40) (actual time=0.001..0.001 rows=1 loops=1)
                    Output: documents_4.id, documents_4.no
                    Buffers: shared hit=1
              ->  Seq Scan on public.documents_5  (cost=0.00..21.60 rows=1160 width=40) (actual time=0.001..0.001 rows=1 loops=1)
                    Output: documents_5.id, documents_5.no
                    Buffers: shared hit=1
...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38556941
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
sp
Код: 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.
Subquery Scan on documents  (cost=1.55..149.56 rows=2 width=72) (actual time=0.057..0.067 rows=3 loops=1)
  Output: documents.id, documents.no
  Filter: (((documents.no)::integer > 100) AND ((documents.no)::integer < 300))
  Rows Removed by Filter: 7
  Buffers: shared hit=7
        Buffers: shared hit=7
        ->  Append  (cost=0.00..109.00 rows=5801 width=40) (actual time=0.006..0.013 rows=10 loops=1)
              Buffers: shared hit=6
              ->  Seq Scan on public.documents  (cost=0.00..1.00 rows=1 width=40) (actual time=0.004..0.004 rows=0 loops=1)
                    Output: documents.id, documents.no
                    Buffers: shared hit=1
              ->  Seq Scan on public.documents_1  (cost=0.00..21.60 rows=1160 width=40) (actual time=0.001..0.002 rows=5 loops=1)
                    Output: documents_1.id, documents_1.no
                    Buffers: shared hit=1
              ->  Seq Scan on public.documents_2  (cost=0.00..21.60 rows=1160 width=40) (actual time=0.001..0.001 rows=2 loops=1)
                    Output: documents_2.id, documents_2.no
                    Buffers: shared hit=1
              ->  Seq Scan on public.documents_3  (cost=0.00..21.60 rows=1160 width=40) (actual time=0.001..0.001 rows=1 loops=1)
                    Output: documents_3.id, documents_3.no
                    Buffers: shared hit=1
              ->  Seq Scan on public.documents_4  (cost=0.00..21.60 rows=1160 width=40) (actual time=0.001..0.001 rows=1 loops=1)
                    Output: documents_4.id, documents_4.no
                    Buffers: shared hit=1
              ->  Seq Scan on public.documents_5  (cost=0.00..21.60 rows=1160 width=40) (actual time=0.001..0.001 rows=1 loops=1)
                    Output: documents_5.id, documents_5.no
                    Buffers: shared hit=1




у вас условие по (((documents.no)::integer > 100) AND ((documents.no)::integer < 300))
а партиционирование по: partition1 - CHECK ( ContractNo::int <= 100 AND ContractNo::int > 0 )
...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38556953
sp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim Boguk,

в данном случае названия полей не играют роли - в начале я назвал ContractNo но потом переименовал в no - вы же понимаете что ПЖ не дал бы создать CHECK если указать неверное поле )
...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38556968
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
spMaxim Boguk,

в данном случае названия полей не играют роли - в начале я назвал ContractNo но потом переименовал в no - вы же понимаете что ПЖ не дал бы создать CHECK если указать неверное поле )
не знаю, что у вас не играет

делаем полный тест-кейс:
Код: sql
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.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
--DDL--
DROP TABLE IF EXISTS documents CASCADE ;

CREATE TABLE documents  
(id serial primary key
,"no" varchar (5))
;


CREATE TABLE documents_1 (
LIKE documents 
,CHECK ( "no"::int <= 100 AND  "no"::int > 0 )
)
INHERITS (documents);

CREATE TABLE documents_2 (
LIKE documents 
,CHECK ( "no"::int <= 200 AND  "no"::int >100 )
)
INHERITS (documents);

CREATE TABLE documents_3(
LIKE documents 
,CHECK ( "no"::int <= 300 AND  "no"::int >200 )
)
INHERITS (documents);

CREATE TABLE documents_4(
LIKE documents 
,CHECK ( "no"::int <= 400 AND  "no"::int >300 )
)
INHERITS (documents);

CREATE TABLE documents_5(
LIKE documents 
,CHECK ( "no"::int <= 500 AND  "no"::int >400 )
)
INHERITS (documents);
--- триггера писать не буду, с в.п.--
-- ADD TEST DATA ---
do
$do$
DECLARE
	v_sql text;
	k int;
BEGIN
FOR i IN 1..100000
LOOP
	k:=(i %500)/100+1;
	v_sql='
	INSERT INTO documents_'||trim(k::text)||'(id,no) 
	VALUES (DEFAULT,'||((i%500)+1)||');';
	EXECUTE v_sql;
END LOOP;
END;
$do$;
------------------------------
-- TEST --
set constraint_exclusion = on;
EXPLAIN select * from documents where "no"::int > 100 and "no"::int < 300;
--
"Append  (cost=0.00..1178.00 rows=201 width=8)"
"  ->  Seq Scan on documents  (cost=0.00..0.00 rows=1 width=28)"
"        Filter: (((no)::integer > 100) AND ((no)::integer < 300))"
"  ->  Seq Scan on documents_2  (cost=0.00..589.00 rows=100 width=8)"
"        Filter: (((no)::integer > 100) AND ((no)::integer < 300))"
"  ->  Seq Scan on documents_3  (cost=0.00..589.00 rows=100 width=8)"
"        Filter: (((no)::integer > 100) AND ((no)::integer < 300))"
---


ЧЯДНТ ?
...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38557003
sp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qwwq,

спасибо - разобрался - секционирование работает на запросах к таблице, не работает view на секционированной таблице
Чтоб не перегружать пост не писал. что выборку делаю из view:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
CREATE OR REPLACE VIEW public.documents_view(
    id,
    no)
AS
  SELECT documents.id,
         documents.no
  FROM documents;



как сделать чтоб view учитывало constraint_exclusion - не пойму
...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38557053
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
spqwwq,

спасибо - разобрался - секционирование работает на запросах к таблице, не работает view на секционированной таблице
Чтоб не перегружать пост не писал. что выборку делаю из view:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
CREATE OR REPLACE VIEW public.documents_view(
    id,
    no)
AS
  SELECT documents.id,
         documents.no
  FROM documents;



как сделать чтоб view учитывало constraint_exclusion - не пойму

а что будет если написать?

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
explain analyze
select * from
(
  SELECT documents.id as id,
         documents.no as no
  FROM documents
) as documents_view
where "no"::int > 100 and "no"::int < 300;



вообще очень странно все это...
...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38557060
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim Boguk,

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
"Append  (cost=0.00..1178.00 rows=201 width=8) (actual time=0.042..540.768 rows=39800 loops=1)"
"  ->  Seq Scan on documents  (cost=0.00..0.00 rows=1 width=28) (actual time=0.004..0.004 rows=0 loops=1)"
"        Filter: (((no)::integer > 100) AND ((no)::integer < 300))"
"  ->  Seq Scan on documents_2  (cost=0.00..589.00 rows=100 width=8) (actual time=0.019..108.907 rows=20000 loops=1)"
"        Filter: (((no)::integer > 100) AND ((no)::integer < 300))"
"  ->  Seq Scan on documents_3  (cost=0.00..589.00 rows=100 width=8) (actual time=0.025..106.899 rows=19800 loops=1)"
"        Filter: (((no)::integer > 100) AND ((no)::integer < 300))"
"        Rows Removed by Filter: 200"
"Total runtime: 706.097 ms"

...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38557070
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim Boguk,

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
BEGIN;
CREATE VIEW documents_view AS 
SELECT documents.id as id,
         documents.no as no
  FROM documents;
explain analyze

select * from
  documents_view
where "no"::int > 100 and "no"::int < 300;
---------------------
"Append  (cost=0.00..1178.00 rows=201 width=8) (actual time=0.055..533.910 rows=39800 loops=1)"
"  ->  Seq Scan on documents  (cost=0.00..0.00 rows=1 width=28) (actual time=0.004..0.004 rows=0 loops=1)"
"        Filter: (((no)::integer > 100) AND ((no)::integer < 300))"
"  ->  Seq Scan on documents_2  (cost=0.00..589.00 rows=100 width=8) (actual time=0.032..109.195 rows=20000 loops=1)"
"        Filter: (((no)::integer > 100) AND ((no)::integer < 300))"
"  ->  Seq Scan on documents_3  (cost=0.00..589.00 rows=100 width=8) (actual time=0.018..102.198 rows=19800 loops=1)"
"        Filter: (((no)::integer > 100) AND ((no)::integer < 300))"
"        Rows Removed by Filter: 200"
"Total runtime: 691.274 ms"
---------------------------
"ЧЯДНТ"

...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38557100
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qwwqMaxim Boguk,

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
"Append  (cost=0.00..1178.00 rows=201 width=8) (actual time=0.042..540.768 rows=39800 loops=1)"
"  ->  Seq Scan on documents  (cost=0.00..0.00 rows=1 width=28) (actual time=0.004..0.004 rows=0 loops=1)"
"        Filter: (((no)::integer > 100) AND ((no)::integer < 300))"
"  ->  Seq Scan on documents_2  (cost=0.00..589.00 rows=100 width=8) (actual time=0.019..108.907 rows=20000 loops=1)"
"        Filter: (((no)::integer > 100) AND ((no)::integer < 300))"
"  ->  Seq Scan on documents_3  (cost=0.00..589.00 rows=100 width=8) (actual time=0.025..106.899 rows=19800 loops=1)"
"        Filter: (((no)::integer > 100) AND ((no)::integer < 300))"
"        Rows Removed by Filter: 200"
"Total runtime: 706.097 ms"



у меня что для view что для таблицы план одинаковый


Код: plaintext
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.
[local]:5432 postgres@temp=# EXPLAIN select * from documents where "no"::int > 100 and "no"::int < 300;
                                      QUERY PLAN
--------------------------------------------------------------------------------------
 Result  (cost=0.00..2617.80 rows=201 width=8)
   ->  Append  (cost=0.00..2617.80 rows=201 width=8)
         ->  Seq Scan on documents  (cost=0.00..0.00 rows=1 width=28)
               Filter: (((no)::integer > 100) AND ((no)::integer < 300))
         ->  Seq Scan on documents_2 documents  (cost=0.00..1308.90 rows=100 width=8)
               Filter: (((no)::integer > 100) AND ((no)::integer < 300))
         ->  Seq Scan on documents_3 documents  (cost=0.00..1308.90 rows=100 width=8)
               Filter: (((no)::integer > 100) AND ((no)::integer < 300))
(8 rows)

Time: 2.260 ms
[local]:5432 postgres@temp=# EXPLAIN select * from documents_view where "no"::int > 100 and "no"::int < 300;
                                      QUERY PLAN
--------------------------------------------------------------------------------------
 Result  (cost=0.00..2617.80 rows=201 width=8)
   ->  Append  (cost=0.00..2617.80 rows=201 width=8)
         ->  Seq Scan on documents  (cost=0.00..0.00 rows=1 width=28)
               Filter: (((no)::integer > 100) AND ((no)::integer < 300))
         ->  Seq Scan on documents_2 documents  (cost=0.00..1308.90 rows=100 width=8)
               Filter: (((no)::integer > 100) AND ((no)::integer < 300))
         ->  Seq Scan on documents_3 documents  (cost=0.00..1308.90 rows=100 width=8)
               Filter: (((no)::integer > 100) AND ((no)::integer < 300))
...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38557166
qwwq
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim Boguk<>

у меня что для view что для таблицы план одинаковый

<>
"аналогично"(сс)
...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38557214
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qwwqMaxim Boguk<>

у меня что для view что для таблицы план одинаковый

<>
"аналогично"(сс)

опять автор топика какую то критичную инфу не выдал "Чтоб не перегружать пост"
(к этому бы еще понимание что критично а что нет :))
...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38557373
sp
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Maxim Boguk,

:) вы правы - утаил WITH(security_barrier = true) с ним и не работает...а надо
...
Рейтинг: 0 / 0
Использование record в CHECK constarint
    #38557385
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
spMaxim Boguk,

:) вы правы - утаил WITH(security_barrier = true) с ним и не работает...а надо

и не будет... никакие условия не вносятся под security barrier... такой view скорее всего будет вычислять всегда полный запрос внутри а потом уже накладывать все остальные условия поверх... на то он и barrier
...
Рейтинг: 0 / 0
25 сообщений из 42, страница 1 из 2
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Использование record в CHECK constarint
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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