테이블에 행이없는 경우 행을 삽입 한 다음 행의 ID를 반환하는 함수를 사용하고 있습니다.
SELECT
아직 테이블에 존재하지 않는 값 으로 명령문 안에 함수를 넣을 때마다 , 예 :
SELECT * FROM table WHERE id = function(123);
... 빈 행을 반환합니다. 그러나 동일한 값으로 다시 실행하면보고 싶은 값이있는 행이 반환됩니다.
왜 이런 일이 발생합니까? 는 IS INSERT
뒤에서 실행 SELECT
속도는? 아니면 PostgreSQL이 테이블이 존재하지 않았을 때 캐시하고 다음 실행시 결과를 표시합니까?
이 문제가 발생하는 방법에 대한 사용 가능한 예는 다음과 같습니다.
CREATE TABLE IF NOT EXISTS test_table(
id INTEGER,
tvalue boolean
);
CREATE OR REPLACE FUNCTION test_function(user_id INTEGER)
RETURNS integer
LANGUAGE 'plpgsql'
AS $$
DECLARE
__user_id INTEGER;
BEGIN
EXECUTE format('SELECT * FROM test_table WHERE id = $1')
USING user_id
INTO __user_id;
IF __user_id IS NOT NULL THEN
RETURN __user_id;
ELSE
INSERT INTO test_table(id, tvalue)
VALUES (user_id, TRUE)
RETURNING id
INTO __user_id;
RETURN __user_id;
END IF;
END;
$$;
요구:
SELECT * FROM test_table WHERE id = test_function(4);
문제를 재현하려면 아직 테이블에없는 정수를 전달하십시오.
예제는 여러 곳에서 나뉩니다.
EXECUTE
.SELECT *
기능이 잘못되었습니다.UNIQUE
또는 PRIMARY KEY
제약 조건 이 있어야합니다 (id)
.가장 중요한 것은 최종 SELECT
진술이 실패 할 수밖에 없다는 것입니다. 때문에 함수이다VOLATILE
(수 있음), 이것은 한 번씩 평가 각 테이블의 기존 행. 그게 효과가 있더라도 성능 악몽이 될 것입니다. 그러나 그렇지 않습니다. @ user2864740이 댓글을 단 것처럼 가시성 에도 문제 가 있습니다 . Postgres는 함수의 결과에 대해 기존의 모든 행을 확인 합니다. 그러면 1 개 이상의 행이 추가되고 해당 행은 아직 SELECT
작동중인 스냅 샷에 없습니다 .
SELECT * FROM test_table WHERE id = test_function(4);
이것은 작동 할 것입니다 (그러나 아래 참조!) :
CREATE TABLE test_table (
id int PRIMARY KEY --!
, tvalue bool
);
CREATE OR REPLACE FUNCTION test_function(_user_id int)
RETURNS test_table LANGUAGE sql AS
$func$
WITH ins AS (
INSERT INTO test_table(id, tvalue)
VALUES (_user_id, TRUE)
ON CONFLICT DO NOTHING
RETURNING *
)
TABLE ins
UNION ALL
SELECT * FROM test_table WHERE id = _user_id
LIMIT 1
$func$;
그리고 다음으로 교체하십시오 SELECT
.
SELECT * FROM test_function(1);
db <> 여기에 바이올린
관련 :
동시 호출 에는 여전히 경쟁 조건 이 있습니다 . 그럴 수 있다면 다음을 고려하십시오.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다