2015-09-05 67 views
1

我正在使用PostgreSQL 9.1。假設我有一張表,其中一些列有約束條件UNIQUE。最簡單的例子:SQL - 依賴於INSERT期間的服務器錯誤

CREATE TABLE test (
    value INTEGER NOT NULL UNIQUE 
); 

現在,插入一些值的時候,我不得不單獨處理的情況下,在要插入的值已經在表中。我有兩個選擇:

  • 做一個SELECT事先保證的值不在表中,或:
  • 執行INSERT,看服務器可能會返回任何錯誤。

使用PostgreSQL數據庫的應用程序是用Ruby編寫的。下面是我將如何編寫第二個選項:

require 'pg' 

db = PG.connect(...) 

begin 
    db.exec('INSERT INTO test VALUES (66)') 
rescue PG::UniqueViolation 
    # ... the values are already in the table 
else 
    # ... the values were brand new 
end 

db.close 

這裏是我的想法:讓我們假設我們做一個SELECT第一,插入前。 SQL引擎必須掃描行並返回任何匹配的元組。如果沒有,我們做一個INSERT,這可能是另一次掃描,看是否約束不會被任何機會侵犯。所以,從理論上講,第二種選擇會使執行速度提高50%。這是PostgreSQL實際上的行爲方式嗎?

當涉及到異常本身時(例如,我們只有一個UNIQUE約束),我們假設沒有歧義。

這是常見的做法嗎?或者有任何警告嗎?還有更多的選擇嗎?

回答

2

這取決於 - 如果您的應用程序UI通常允許輸入重複值,那麼強烈建議您在插入前進行檢查。因爲任何錯誤都會使當前事務無效,消耗順序/序列值,填充錯誤消息等日誌。

但是,如果您的用戶界面不允許重複,並且插入重複只能在有人使用技巧時進行(例如在漏洞研究)或極不可能的,那麼我會允許插入而不先檢查。

由於唯一性約束強制創建索引,因此此檢查並不慢。但肯定比插入和檢查罕見錯誤稍慢。 Postgres 9.5 would have on conflict do nothing support,這將是既快速又安全。您將檢查插入的行數以檢測重複項。

+0

+1'ON CONFLICT'和檢查數量的插入行。 「ON CONFLICT」的官方文檔是[here](http://www.postgresql.org/docs/devel/static/sql-insert.html#SQL-ON-CONFLICT)。 –

+0

UI反映了數據庫本身的結構 - 並且由於我在數據庫中聲明瞭'UNIQUE'約束,因此UI不允許重複。建議的'ON CONFLICT'語法和檢查插入行的數量看起來像是一個完美的SQL-only-ish選擇。太糟糕了,我不會有任何機會把它放在它上面。 – Tomalla

1

你沒有(也不應該)必須先測試;你可以測試而插入。只需將測試作爲where子句添加即可。以下插入插入零或一個元組,取決於具有相同值的行的存在。 (它肯定是較慢):

INSERT INTO test (value) 
SELECT 55 
WHERE NOT EXISTS (
    SELECT * FROM test 
    WHERE value = 55 
    ); 

雖然你的錯誤驅動方法可能外觀典雅從客戶端,從數據庫方面,它是一個近乎災難:當前事務隱式回滾+所有遊標(包括預準備語句)都關閉。 (因此:您的應用程序將不得不重建完整的交易,但沒有錯誤並重新開始。)


增加:增加多行的時候就可以把VALUES()成CTE和參考CTE中插入查詢:

WITH vvv(val) AS (
    VALUES (11),(22),(33),(44),(55),(66) 
    ) 
INSERT INTO test(value) 
SELECT val FROM vvv 
WHERE NOT EXISTS (
    SELECT * 
    FROM test nx 
    WHERE nx.value = vvv.val 
    ); 

-- SELECT * FROM test; 
+0

感謝您使用替代SQL語法。儘管我沒有在問題中明確地說出它,但我還在單個INSERT語句中插入了多行,如下所示:INSERT INTO VALUES(66),(67);'。您提供的語句是否可以修改爲允許插入多行?關於錯誤驅動的解決方案:一旦SQL服務器返回錯誤,客戶端請求正在處理**完成**並返回。它不會從錯誤中恢復,因爲錯誤本身會導致請求不正確。所以這種方法仍然很高,因爲它看起來更快,語義更準確。 – Tomalla