最近我有一個有趣的設計決定。假設我將用戶名添加到表中,並且要確保沒有重複。用戶名列是NOT NULL UNIQUE
。我既可以:我應該通過數據庫錯誤強制執行業務邏輯嗎?
- 查詢插入,以確保沒有重複的名字,或
- 只是
INSERT
,並且趕上來自數據庫引擎的任何異常前的數據庫。
假設我使用DB能夠執行的限制,我想知道什麼情況下,每一種選擇是適當的。
最近我有一個有趣的設計決定。假設我將用戶名添加到表中,並且要確保沒有重複。用戶名列是NOT NULL UNIQUE
。我既可以:我應該通過數據庫錯誤強制執行業務邏輯嗎?
INSERT
,並且趕上來自數據庫引擎的任何異常前的數據庫。假設我使用DB能夠執行的限制,我想知道什麼情況下,每一種選擇是適當的。
你想到的是,新的用戶名很可能是獨一無二的?或者它可能會重複?如果用戶名可能是唯一的,那麼執行插入和捕獲異常將更有效。如果用戶名可能是重複的,那麼檢查重複項(並且可能尋找類似的但尚未被使用的用戶名)而不是嘗試捕捉異常會更有效。顯然不同的數據庫和不同版本的數據庫在相對概率上有不同的平衡點。但總的來說,如果您正在爲每個人都擁有唯一用戶名的公司構建系統,請執行插入並捕獲異常。如果您正在構建Hotmail,請首先檢查重複項。
快速演示(在Oracle 11.2.0.1上)顯示,執行插入失敗並處理異常的插入操作比插入前執行檢查然後寫入數據的開銷大約高出7倍。
SQL> create table username_test (
2 username varchar2(30) unique
3 );
Table created.
SQL> set timing on;
SQL> ed
Wrote file afiedt.buf
1 declare
2 l_cnt integer;
3 begin
4 for i in 1 .. 100000
5 loop
6 select count(*)
7 into l_cnt
8 from username_test
9 where username = 'JCAVE';
10 if(l_cnt = 0)
11 then
12 insert into username_test(username)
13 values('JCAVE');
14 end if;
15 end loop;
16* end;
SQL>/
PL/SQL procedure successfully completed.
Elapsed: 00:00:04.20
SQL> rollback;
Rollback complete.
Elapsed: 00:00:00.00
SQL> ed
Wrote file afiedt.buf
1 declare
2 l_cnt integer;
3 begin
4 for i in 1 .. 100000
5 loop
6 begin
7 insert into username_test(username)
8 values('JCAVE');
9 exception
10 when dup_val_on_index then
11 null;
12 end;
13 end loop;
14* end;
SQL>/
PL/SQL procedure successfully completed.
Elapsed: 00:00:29.58
它幾乎總是似乎是一個好主意,做選項2.我不建議選擇1,因爲你已經提高了一倍的時間做插入所需的量(它們都需要讀取第一)。此外,一些新的開發人員只會在某個時候提交而不是支票,並且會被破壞。
要考慮的另一件事是多少停機時間是合適的?這是一個關鍵任務應用程序嗎?如果業務邏輯損壞會發生什麼?如果工廠關閉,工廠會關閉嗎?或者它會只是一些煩人的錯誤。
你不能讓你的工廠關閉,因爲你沒有想到的一些例外會導致服務器崩潰。因此,在這種情況下,對數據正確性進行每晚或每週檢查也可能有所幫助。但是,我覺得DB強制執行唯一性(以及其他強制執行)的能力是適當的方式。
你可以緩存用戶名列表,並檢查它在應用程序端而不去數據庫?您應該仍然對數據庫有唯一的約束,以確保沒有錯誤的數據進入(始終首先保護數據庫級別的數據),但是如果您可以從緩存中執行檢查,則可以將整個往返保存到數據庫,當有人選擇與現有用戶相同的用戶名。現在這可能取決於您需要緩存的數據的大小以及緩存的更新頻率。不知道你的系統,我不能說它是否實用,但我至少會考慮這樣做。
您是否暗示執行兩個查詢(一個檢查和一個插入)比單純執行插入並查看它是否失敗要快?我必須看到一個基準,表明這是因爲它看起來不合邏輯。 – corsiKa 2011-02-18 15:21:13
@ glowcoder - 是的,我是。請記住,異常處理是昂貴的 - 它應該在發生意外事件時使用。單行檢查通常比處理異常要便宜。 – 2011-02-18 15:24:12