为什么尽量避免使用触发器

为什么尽量避免使用触发器
   上次没有具体说明,宽宽一直在追问这个问题,现在补充如下:
     如果你是使用的SQL2000,这个问题会更加严重。触发器操作要作为外部事务的一部分,因此instered和deleted两个虚拟表都是写到事务日志中的。因为日志是顺序写入的,所以在把新旧记录写入日志时,会阻止其它事务写入。同时,读取日志时也会因为有其它写入时而被阻塞。这个无疑给并发操作带来很大影响。
     SQLSERVER在内部会把触发器作为一个存储过程来对待,除了不能输入参数等限制外。另一个值得考虑的问题是触发器的执行计划问题,它不随过程的重新编译而编译。上次演示过因为错误的缓存导致的错误的执行计划示例,不知道这个算不算作一个问题。
     现在SQL2005的新旧记录不再保存在日志中,而是使用新的行版本技术存储于tempdb中。这带来了一定程度上的并发优势,但是维护这些版本记录同样也需要额外的开销。同时,在这样的版本链列表中寻找记录也一样会有性能损耗。现在2005的update、delete、insert操作都带了output子句,可以使用它来替换触发器的操作。但是output有个限制是不能直接into到有约束的表,如果有约束也可以先把前后记录存入一个临时的地方再做进一步处理。
    下面的代码演示了使用output和trigger时,所观察到的情况,两者都会用到tempdb。但是output是在自己独有的空间中存储这些记录的,而trigger则是在一个公用的空间中存储就像是私家车库与公用停车场一样。因此output会更专职于处理某个请求的操作。具体代码如下:

--更新所有在London的供应商的产品体格为原价格的1.5倍
 USE Northwind;
 GO
 --创建价格变动历史记录表
 IF OBJECT_ID('Price_history','U') IS NOT NULL
     DROP TABLE Price_history
 GO
 SELECT 1 AS ProductID,UnitPrice AS OldPrice,UnitPrice AS NewPrice,GETDATE() AS Date
 INTO Price_history
 FROM dbo.Products
 WHERE 1=0
 GO
 IF OBJECT_ID('trg_Products_u','TR') IS NOT NULL
     DROP TRIGGER trg_Products_u;
 GO
 --sys.dm_tran_version_store用于存储行版本记录所用,此记录在没有被引用的情况下在一分钟内会被清理线程清除
 select * from sys.dm_tran_version_store--确保此时没有版本记录存在
 --请确保Products表现在没有任何其它更新触发器存在
 --更新完成后发现没有记录相应的行版本,
--如果你打开性能计数器跟踪SQLSERVER:TRANSACTIONS对象的free space in tempdb,你会发现它确实也用到了tempdb。
--因为这个更新没有多少记录,看不出结果。你可以换一个Sales.SalesOrderDetail表来试一下。
 update p
 set UnitPrice=UnitPrice*1.5
 output deleted.ProductID,deleted.UnitPrice,inserted.UnitPrice,getdate() into price_history
 from dbo.Products p
     join dbo.Suppliers s
     on p.SupplierID=s.SupplierID
 where s.city=N'London'
 select * from sys.dm_tran_version_store
 
 GO
 
 --现在我们创建一个更新触发器来完成此功能
 IF OBJECT_ID('trg_Products_u','TR') IS NOT NULL
     DROP TRIGGER trg_Products_u;
 GO
 CREATE TRIGGER trg_Products_u ON dbo.Products FOR UPDATE
 AS
 --如果更新的不是UnitPrice或没有更新直接返回
 IF NOT UPDATE(UnitPrice) OR @@ROWCOUNT=0
     RETURN;
 ELSE
     INSERT INTO price_history
     SELECT i.ProductID,d.UnitPrice,i.UnitPrice,getdate()
     FROM inserted i
         join deleted d
         on i.ProductID=d.ProductID
 GO
 --使用触发器时,完成更新查看版本记录中有6条记录
 --因为在'London'的供应商有三个产品,所以新旧记录加起来总共是6条记录
 
 update p
 set UnitPrice=UnitPrice*1.5
 from dbo.Products p
     join dbo.Suppliers s
     on p.SupplierID=s.SupplierID
 where s.city=N'London'
 select * from sys.dm_tran_version_store
 
 
 DBCC FREEPROCCACHE;--清除过程缓存以观察触发器的缓存计划
 GO
 
 --创建显示重新编译的存储过程
 SET ANSI_NULLS ON
 GO
 SET QUOTED_IDENTIFIER ON
 GO
 IF OBJECT_ID('prc_UpdateProductPrice','P') IS NOT NULL
     DROP PROC prc_UpdateProductPrice;
 GO
 CREATE PROCEDURE prc_UpdateProductPrice
 WITH RECOMPILE
 AS
 BEGIN
     SET NOCOUNT ON;
     update p
     set UnitPrice=UnitPrice*1.5
     from dbo.Products p
         join dbo.Suppliers s
         on p.SupplierID=s.SupplierID
     where s.city=N'London'
 END
 GO
 EXEC prc_UpdateProductPrice
 GO
 --反复执行上述过程后,发现触发器的执行计划不会因为过程的重新编译而被重新编译
 --这可能会因为缓存的原因,造成优化器错误的选择了执行计划
 --不知道这个结果是喜是忧
 SELECT usecounts, cacheobjtype, objtype, text
 FROM sys.dm_exec_cached_plans
 CROSS APPLY sys.dm_exec_sql_text(plan_handle)
 GO

0 0 0
(请您对文章做出评价)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
关系型数据库性能体系,设计和效率提升 1 1 前言 2 1.1目的 2 1.2预期的读者和阅读建议 2 2 数据库模型设计规范 2 2.1 数据库建模原则性规范 2 2.2 实体型之间关系认定规范 2 2.3 范式化1NF的规范 3 2.4 范式化2NF的规范 4 2.5 范式化3NF的规范 4 2.5 反范式化冗余字段使用规范 4 2.6 数据库对象命名基本规范 5 2.6.1遵循行业规范 5 2.6.2简单命名原则 5 2.6.3 字符范围原则 5 2.6.4字母全部大写或小写原则 6 2.6.5勿用保留词原则 6 2.6.5同义性原则 6 2.6.6富有含义原则 6 2.6.7 扩展性原则 6 3 表的设计规范 6 3.1 命名规范 6 3.1.1 表的命名规范 6 3.1.2 字段的命名规范 7 3.2 表的设计规范 7 3.2.1 指定表空间规范 7 3.2.2 表的主键规范 7 3.2.3 表的外键规范 8 3.2.4 字段类型及宽度的规范 8 3.2.5 一个表所含字段总长度的规范 8 3.2.6 一个表所含字段访问频繁度的规范 8 3.2.7 大对象字段(BLOB,CLOB)使用规范 9 3.2.8 关于字段能否为NULL值 9 3.2.9 关于冗余列的规范 9 3.2.10 使用注释的规范 9 3.2.11 一个表所含数据量的规范 10 3.2.12 增量同步表的设计规范 10 3.3 字段类型规范 10 3.3.1 不使用会发生隐式转换:INTEGER,FLOAT 10 3.3.2 不使用过时老类型:RAW,LONG,LONG RAW 10 3.3.3 国家字符集相关 10 3.3.4 不能使用大对象:BLOB,CLOB,NCLOB 11 3.3.5 不能使用高精度:TIMESTAMP 11 3.3.6 关于CHAR字段 11 4 分区表的设计规范 11 4.1 表空间及分区表的概念 11 4.1.1 表空间 11 4.1.2 分区表 11 4.2 表分区的具体作用 11 4.3 表分区的优缺点 12 4.4 分区表设计规范 12 4.2.1 不使用全局索引 12 4.2.2 RANGE分区的规范 12 4.2.3 LIST分区的规范 13 4.2.4 HASH分区的规范 13 4.2.5 RANGE-LIST分区的规范 14 4.2.6 RANGE-HASH分区的规范 14 5 索引的设计规范 15 5.1 索引分类 15 5.1.1单列索引与复合索引 15 5.1.2 唯一索引与非唯一索引 15 5.1.3 B树索引、位图索引与函数索引 15 5.2 命名规范 15 5.3 索引设计规范 15 5.3.1 指定表空间规范 16 5.3.2 主键索引的规范 16 5.3.3 唯一约束索引的规范 17 5.3.4 外键列索引的规范 17 5.3.5 复合索引的规范 17 5.3.6 函数索引的规范 17 5.3.7 位图索引的规范 18 5.3.8 反向索引的规范 18 5.3.9 分区索引的规范 18 5.3.10 索引重建的规范 18 6 其他数据库对象设计规范 18 6.1 命名规范 18 6.2 视图设计规范 19 6.2.1 尽量使用简单的视图,避免使用复杂的视图 19 6.2.2 按照必要性原则建立视图 19 6.3 存储过程、函数、触发器的设计规范 19 6.3.1 关于触发器的设计 19 7 SQL访问规范 20 7.1 尽量不要写复杂的SQL 20 7.2 避免使用SELECT * 20 7.3 INSERT时需写全列名 20 7.4 进行DML操作时使用CTAS进行数据备份 20 7.5 大数据量DML操作分多次执行 21 7.6 使用绑定变量,降低高硬解析 21 7.7 选择最有效率的表名顺序 21 7.8 关注WHERE子句中的连接顺序 21 7.9 用EXISTS替代IN 22 7.10 用表连接替换EXISTS 23 7.11用EXISTS替换DISTINCT 24 7.12 尽量用union all替换union 24 7.13 使用DECODE函数来减少处理时间 24 7.14 尽量避免用order by 25 7.15 用Where子句替换HAVING子句 25 7.16 减少多表关联 25 7.17 避免重复访问 26 7.17.1 使用group by 26 7.17.2 用表更新表 26 7.17.3竖向显示变横向显示 26 7.18 完成事务及时commit 27 7.19数据库连接及时关闭 27 7.20 索引的使用 27 7.20.1避免在索引列上使用函数或运算 27 7.20.2避免改变索引列的类型 28 7.20.3避免在索引列上使用NOT 28 7.20.
数据库设计规范 有限公司 变更记录 "版本号 "修改点说明 "变更日期 "变更人 "审批人 " "V1.0 "创建 " " "EPGL " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " 修改点说明的内容有如下几种:创建、修改(+修改说明)、删除(+删除说明) 目 录 1 编写目的 1 2 数据库策略 1 2.1 数据库对象长度策略 1 2.2 数据完整性策略 1 2.3 规范化设计与性能之间的权衡策略 1 2.4 字段类型的定义与使用策略 1 3 命名规范 3 3.1 数据库命名规则 3 3.2 数据库对象命名的一般原则 3 3.3 表空间(Tablespace)命名规则 4 3.4 表(Table)命名规则 4 3.5 字段命名规则 4 3.6 视图(View)命名规则 4 3.7 序列(Sequence)命名规则 5 3.8 存储过程(Procedure)的命名规则 5 3.9 函数(Function)的命名规则 5 3.10 索引(Index) 命名规范 5 3.11 约束(Constraint) 命名规范 5 4 数据模型产出物规范 5 附录A:xml文件使用说明 7 附录B:保留关键字 8 编写目的 本文的目的是提出针对Oracle数据库的设计规范,使利用Oracle数据库进行设计开发 的系统严格遵守本规范的相关约定,建立统一规范、稳定、优化的数据模型。 参照以下原则进行数据库设计: 1) 方便业务功能实现、业务功能扩展; 2) 方便设计开发、增强系统的稳定性和可维护性; 3) 保证数据完整性和准确性; 4) 提高数据存储效率,在满足业务需求的前提下,使时间开销和空间开销达到优化平 衡。 数据库策略 1) 数据模型全局单一,所有公共的数据模型得到共享。 2) 数据库建模要基于统一的元数据管理机制。 3) 数据库设计遵循关系数据库的规范化理论。 4) OLTP与OLAP分开设计。 1 数据库对象长度策略 数据库字段的长度要考虑业务对象的类型、数据库所用字符集、时间格式来设定出相 对准确的长度,满足业务需要,同时保证数据库的高效,避免不必要的开销。 2 数据完整性策略 1) 必须遵循数据库设计的第二范式,根据业务需要尽量满足第三范式。 2) 数据完整性尽量通过业务逻辑实现,数据库设计应尽量避免使用大量的外键约束,避 免使用触发器。 3 规范化设计与性能之间的权衡策略 数据的标准化有助于消除数据库中的数据冗余。如果数据冗余低,数据的一致性容易 得到保证,如无特殊理由,OLTP系统的设计应当遵循第三范式,对于OLAP系统,为了减 少表间连接查询的操作,提高系统的响应时间,合理的数据冗余是必要的。 4 字段类型的定义与使用策略 1) 数据类型的选用原则 "数据类型 "使用说明 " "CHAR "根据业务数据的特征决定是否使用CH" " "AR类型,例如静态编码、固定年月日" " "的时间字段等,避免数据变长的情况" " "下使用CHAR类型 " "VARCHAR2(N) "Oracle数据库VARCHAR2类型,根据业" " "务数据特征定义适当的长度,定义成" " "偶数长度。 " "REAL、FLOAT、INTEGER、NUEBER "Oracle数据库必须使用NUEBER " "NUMBER(P,S)、NUMERIC (P, "Oracle数据库必须使用NUMBER " "S)、DECIMAL (P, S) " " "DATE "时间类型必须使用DATE " "BLOB(二进制数据)、CLOB(字符数" " "据) " " 2) 数据类型长度的选用参考: 如果以下字段类型和长度能满足设计要求,必须遵循以下字段选用原则 "数据类型 "常用类型 " "CHAR "CHAR(1)本规范不推荐长度不为1的字" " "段使用char类型 " "VARCHAR2(N) "VARCHAR2(2) " " "VARCHAR2(4) " " "VARCHAR2(8) " " "VARCHAR2(10) " " "VARCHAR2(16) " " "VARCHAR2(20) " " "VARCHAR2(30) " " "VARCHAR2(40) " " "VARCHAR2(50) " " "VARCHAR2(100) " " "VARCHAR2(200) " " "VARCHAR2(400) " " "VARCHAR2(1000) " " "VARCHAR2(2000) " "NUMBER " " "NUMBER(P,S) " " "DATE " " "BLOB " " 3) 常用字段定义: 涉及销售额等金额的数值: N

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值