Надежный способ сделать это в данный момент - попробовать вставить и дать ему потерпеть неудачу. Вы можете сделать это на уровне приложения или на уровне Postgres; предполагая, что он не является частью процедуры, выполняемой на сервере, это не имеет большого значения, если это так или иначе, когда дело доходит до производительности, поскольку вы отправляете запрос на сервер и получаете результат. (Если это имеет значение, вам необходимо определить точку сохранения, если вы пытаетесь выполнить транзакцию по той же причине. Или, как указано в ответе Крейга, если у вас много неудачных заявлений.)
В будущих версиях, надлежащее merge
и upsert
находятся на радаре, но как около десятилетия долгой дискуссии предположит их реализации должным образом довольно тернист:
Что касается других опций, о которых вы упомянули, указанные выше страницы вики и ссылки внутри них должны подчеркнуть трудности. В принципе, использование подзаголовка является дешевым, как отметил Эрвин, но не является доказательством параллелизма (если вы не заблокируете его правильно); использование блокировок в основном сводится к блокировке всей таблицы (тривиальная, но не большая) или изобретать колесо, которое подделывается в ядре (тривиально для существующих строк, а тем более для потенциально новых, которые вставлены одновременно, если они пытаются использовать предикаты вместо таблицы, блокировка уровня); и использование транзакции и перехват исключения - это то, что вы в конечном итоге сделаете.
Хороший вопрос. По моему опыту, подзапрос с «НЕ СУЩЕСТВУЕТ» самый дешевый (хотя только 99,99% безопасен в отношении условий гонки), но я не могу указывать числа на стоимость повышения исключения. Это также во многом зависит от скорости ключевых столкновений. –