PostgreSQL - дублирующий уникальный ключ - PullRequest
2 голосов
/ 21 июля 2011

У меня на столе есть вторичный уникальный ключ с меткой md5.Перед вставкой я проверяю, существует ли MD5, и, если нет, вставьте его, как показано ниже:

-- Attempt to find this item
SELECT INTO oResults (SELECT domain_id FROM db.domains WHERE "md5"=oMD5);

IF (oResults IS NULL) THEN

    -- Attempt to find this domain
    INSERT INTO db.domains ("md5", "domain", "inserted") 
        VALUES (oMD5, oDomain, now());

    RETURN currval('db.domains_seq');

  END IF;

Это прекрасно работает для однопоточных вставок, моя проблема в том, что у меня есть два внешних приложения, вызывающихмоя функция одновременно, что случается, имеют тот же MD5.Я в конечном итоге в ситуации, когда:

Приложение 1: видит MD5 не существует

Приложение 2: вставляет этот MD5 в таблицу

Приложение 1: идет сейчас ВставитьMD5 в таблицу, поскольку он думает, что он не существует, но получает ошибку, потому что сразу после того, как он увидел, что его нет, приложение 2 вставило его.

Есть ли более эффективный способ сделать это?

Могу ли я отловить ошибку при вставке и, если да, то выбрать domain_id?

Заранее спасибо!


Кажется, это также рассматривается в Вставить, при повторном обновлении в PostgreSQL?

1 Ответ

2 голосов
/ 21 июля 2011

Вы могли бы просто пойти дальше и попытаться вставить MD5 и поймать ошибку, если вы получаете ошибку «уникального нарушения ограничения», затем проигнорируйте ее и продолжайте, если вы получите какую-то другую ошибку, а затем выведите ее из строя. Таким образом, вы отправляете проверку дубликатов прямо в базу данных, и ваше состояние гонки исчезает.

Примерно так:

  • Попытка вставить значение MD5.
    • Если вы получили уникальную ошибку нарушения, игнорируйте ее и продолжайте.
    • Если вы получили какую-то другую ошибку, выручите и пожаловайтесь.
    • Если вы не получили ошибку, продолжайте.
  • Сделайте SELECT INTO oResults (SELECT domain_id FROM db.domains WHERE "md5"=oMD5), чтобы извлечь domain_id.

Возможно, что производительность немного снижена, но «правильно и немного медленно» лучше, чем «быстро, но не работает».

В конечном итоге вы можете получить больше исключений, чем при успешной вставке. Затем вы можете попытаться вставить в таблицу ссылки (через внешний ключ) вашего db.domains и отловить там нарушение FK. Если у вас было нарушение FK, выполните старую «вставку и игнорируйте уникальные нарушения» на db.domains, а затем повторите попытку вставки, которая дала вам нарушение FK. Это та же самая базовая идея, это просто вопрос выбора, который, вероятно, выбросит наименьшее количество исключений и пойдет с этим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...