八卦一下自家管理系统数据库设计方面的几个问题(2)
时间:2011-01-05 来源:陈伟强
SELECT M.BZJGID, C.DJBH, C.SL--, And Some Other Fields
FROM CLDJ C
JOIN MasterDJ M ON M.ID = C.MasterDJID
WHERE EXISTS(SELECT 1/0 FROM RIGHT R WHERE R.DJLX = M.DJLX AND R.FilterType = 1) --SegmentA
OR
EXISTS(
SELECT 1/0 FROM ReportFlow RF WHERE RF.DataID = M.DJID --SegmentB
AND
EXISTS(SELECT 1/0 FROM RIGHT R WHERE R.DJLX = M.DJLX AND R.OrgID = M.BZJGID))--SegmentC
这段代码只是一个片段。只涉及了几个方面。一般来讲,以CLDJ表100,000条记录的一个数量级,整段代码的LogicalReads在大约800,000左右。具体到各个表,大约为:
Right表:400,000
CLDJ表:200,000
这当中的主要问题包括:
1.A段过滤条件是常量过滤,也就是说,在具体到某个单据类型时,这个条件的结果是一定的。
实际上这段代码更适合使用If..Else逻辑来实现。不过考虑到段A和段C两个过滤条件的OR逻辑关系,实现If..Else需要将整段代码分割成两段。难度不大,但是..包袱问题不好解决。
2.段A和段C的Or逻辑关系基本无法生成高效的执行计划(即使段A不是常量过滤条件也是情况也基本如此)。
我们几乎已经接受了这样一个概念:数据库优化器功能是有限的。但是有时候机器的弱智行为还是会让人气愤。
3.段B和段C的嵌套层次比较深,简单逻辑复杂化造成实际执行效果很差
这个问题一方面跟范式太高有关系,另一方面涉及聚集键选择问题。这个以后再说。
我觉得,对于这种形式的语句,可以说,至少一半以上的模块会出现。OOP所谓的优势造就了这样一个移动缓慢,效率低下,看似全能战士一样的怪物。唉,无敌的OOP被无敌的包袱打败了。
这段语句如果放在各家的教科书里,一定会被拿来做反面教材。并且因为框架基本不允许修改,我们进行效率优化的时候到了快要疯掉的地步。你说,我八它一卦有啥错?
我个人的倾向还是比较理想的,就是SQL简单化。范式低一些,冗余多一些。别搞这么多连接,别搞这么多相关子查询。我觉得,任何时候,只要执行计划里出现了三层存在父子关系的连接,那基本就可以断定,你就不想让程序跑的太快。
后面再八一下数据库聚集索引设计方面的问题吧。