Стабильная функция, вызывающая энергозависимую функцию: проблема параллелизма - PullRequest
0 голосов
/ 09 сентября 2011

База данных содержит таблицу пользователей. Пользователь добавляется в таблицу всякий раз, когда его имя пользователя является частью данных, отправляемых в базу данных (т. Е. Через функцию), и имя пользователя должно быть уникальным в таблице. Одно имя пользователя также может появляться несколько раз при любом вызове функции.

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

Решение, которое я придумала, - это функция STABLE, которая сначала пытается выбрать из таблицы пользователей, а в случае неудачи вызывает вспомогательную функцию VOLATILE, которая пытается вставить в таблицу пользователя. Я предпочитаю STABLE, потому что результат функции будет таким же для остальной части транзакции, поэтому я хотел бы оптимизировать его в случае, когда имя пользователя было включено несколько раз, или когда оно передается другим функциям, которые также ищет его ID.

У меня вопрос: будет ли STABLE из моей начальной функции означать, что параллельная вставка (вызывающая исключение в вспомогательной функции) никогда не будет видна исходной функции и, таким образом, вызовет бесконечный цикл?

Я включил определения ниже.

CREATE SCHEMA orgnztn;
CREATE TABLE orgnztn.tUsers (
    id serial NOT NULL,
    usrid text NOT NULL,
    PRIMARY KEY (id),
    UNIQUE (usrid)
);

CREATE OR REPLACE FUNCTION orgnztn.getUserID (
    IN  p_usrid             text
)
    RETURNS integer
    LANGUAGE plpgsql
    STABLE
    CALLED ON NULL INPUT
    SECURITY INVOKER
    AS $$
        DECLARE
            p_id integer;
        BEGIN
            IF p_usrid IS NULL THEN
                RETURN NULL;
            END IF;
            p_usrid = upper(p_usrid);
            LOOP
                SELECT id INTO p_id
                    FROM orgnztn.tUsers
                    WHERE usrid = p_usrid
                    FETCH FIRST 1 ROWS ONLY;
                IF found THEN
                    RETURN p_id;
                END IF;
                BEGIN
                    RETURN orgnztn.getUserID_helper(p_usrid);
                    EXCEPTION WHEN unique_violation THEN
                        -- loop
                END;
            END LOOP;
        END;
    $$;
CREATE OR REPLACE FUNCTION orgnztn.getUserID_helper (
    IN  p_usrid             text
)
    RETURNS integer
    LANGUAGE plpgsql
    VOLATILE
    CALLED ON NULL INPUT
    SECURITY INVOKER
    AS $$
        DECLARE
            p_id integer;
        BEGIN
            INSERT INTO orgnztn.tUsers (usrid)
                VALUES (p_usrid)
                RETURNING id INTO p_id;
            RETURN p_id;
        END;
    $$;

1 Ответ

1 голос
/ 18 сентября 2011

флаги volatile или stable не связаны с параллелизмом. Основное использование этих флагов для оптимизации запросов. Вы должны выбрать один из уровня изоляции транзакции и использовать адекватное решение - зависит от того, используете ли вы уровень REPEATABLE READ или READ COMMITED.

На самом деле функция getUserID должна быть помечена как volatile, потому что она вызывает другую энергозависимую функцию. Если вы используете уровень REPEATABLE READ, то может быть бесконечный цикл.

...