物理结构关系到应用系统的生死存亡, 选择错误的数据结构, 性能达不到要求.
测试示例, 使用触发器进行完整性检查, 触发器是当用户执行SQL语句时, 就会判断触发器, 而不是需要等到最后COMMIT的时候才判断, 比如 利用 scott 模式的emp来完成测试:
要求, emp 表每个部门的行数在 3-8行, 目前emp表满足要求,
1. (session 1 删除一些行, 但是满足触发器, 不提交)
2. session 2 删除一些行, 也满足触发器, 提交
3. 这时候, 再提交session 1, 因为提交的时候触发器已经触发了一次了, 这时候就不会再触发.
4. 那么这两次删除的行数, 已经让这个部门剩下的行小于 3 了.
所以, 用触发器来判断完整性是不合适的. 另外, 要看详细的例子, 就看高效设计 第7章 有完整的例子.
为了解决上边的问题, 我们需要使用一个串行化设备来实现, 我们使用 约束来实现完整性.
-- 1 -- 增加约束, 并延后确认
alter table dept add emp_count number constraint must_be_between 3 and 8 or emp_count = 0) deferrable initially deferred; 蓝色表示提交的时候再验证
-- 2 -- 初始化 emp_count 值
update dept set emp_count = (select count(*) from emp where emp.deptno = dept.deptno )
-- 3 -- 生效约束
alter table dept modified emp_count not null;
-- 4 -- 需要一个触发器维持 emp_count, 主要是为了确认修改 deptno
create trigger emp_dept_cnt_trigger
after insert or update or delete on emp
for each row
begin
if (updating and : old.deptno = : new.deptno) then
return; -- no change
end if ;
if (inserting or updating ) then
update dept set emp_count = emp_count + 1
where deptno = :new.deptno;
end if;
if (updating or deleting ) then
update dept set emp_count = emp_count – 1
where deptno = : old.deptno;
end if;
end;
另外, 有一些, 可以使用客户端的约束来确认. 即 application 确认. 但是, 这个只能作为补充, 主要还是要利用数据库级的完整性约束.
包括类型的精度, 都不是随便的, 比如 varcar2(20), varchar2(200), 有人说, 无所谓, 反正是varchar2类型时变动的, 但是有很多软件, 是根据varchar2的精度来设定单元格的宽度的, 显然20宽度 和 200宽度 相差甚远.
大部分情况是 使用堆表 和 B*树索引.