我最近一直在考虑一个有趣的设计决定。假设我正在将用户名添加到表中,并且我想确保没有重复。用户名列是NOT NULL UNIQUE
。我可以:
- 在插入之前查询数据库以确保没有重复的名称,或者
- 只需
INSERT
, 并捕获来自数据库引擎的任何异常。
假设我使用的数据库能够强制执行约束,我想知道这些选择中的每一个在什么情况下是合适的。
我最近一直在考虑一个有趣的设计决定。假设我正在将用户名添加到表中,并且我想确保没有重复。用户名列是NOT NULL UNIQUE
。我可以:
INSERT
, 并捕获来自数据库引擎的任何异常。假设我使用的数据库能够强制执行约束,我想知道这些选择中的每一个在什么情况下是合适的。
执行选项 2 几乎总是一个好主意。我不推荐选项 1,因为您实际上将执行插入所需的时间加倍(它们都需要先读取)。此外,一些新开发人员会在某个时间提交而不进行检查,它会被破坏。
另一件要考虑的事情是多少停机时间是合适的?这是一个关键任务应用程序吗?如果业务逻辑损坏会发生什么?如果是,工厂会关闭吗?还是只是一些烦人的错误。
你不能让你的工厂因为一些你没想到的异常导致你的服务器崩溃而关闭。因此,在这种情况下,也许每晚或每周检查一次数据的正确性也会有所帮助。但是,我认为数据库强制执行唯一性(以及可能的其他强制执行)的能力是合适的方法。
可以不去数据库缓存用户名列表,在应用端查看吗?您仍然应该对数据库具有唯一约束,以确保没有坏数据进入(始终首先在数据库级别保护数据)但是如果您可以从缓存中进行检查,您可以节省整个往返行程当有人选择与现有用户相同的用户名时的数据库。现在,这可能取决于您需要缓存的数据大小以及必须多久更新一次缓存。不知道你的系统,我不能说它是否实用,但我至少会考虑这样做。
您是否认为新用户名可能是唯一的?或者它很可能是重复的?如果用户名可能是唯一的,那么插入并捕获异常会更有效。如果用户名很可能是重复的,则检查重复项(并可能寻找相似但尚未使用的用户名)比尝试捕获异常更有效。显然,不同的数据库和这些数据库的不同版本在相对概率上具有不同的盈亏平衡点。但一般来说,如果您正在为一家公司构建一个每个人都有唯一用户名的系统,请执行插入并捕获异常。如果您正在构建 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