我正在维护基于Java的旧式货运铁路货运单会计系统的维护人员。检索要在其网站上显示的托运单列表存在严重的性能问题。
我无法发布整个查询,但是下面是一些统计数据,可以大致了解这个问题:
where
子句,带有5个OR组,用于确定是否由于与记录(发货人,收货人,承运人,付款人,主管)的特定关系而允许用户访问记录并进行检查用户访问特定火车站相关记录的许可exists()
检查与记录相关的某些数据的子查询,并检查站的权限。实质上,每个记录对当前登录用户的可用性取决于以下因素: -用户的公司 -每个特定托运单的承运人,收货人,发货人,付款人的公司 -每个托运单都有多个路径部分,每个部分都有自己的承运人和付款人,因此需要进一步的访问控制条件才能使这些记录对用户可见 -每个托运单和每个路线段都有始发站和目的地站,并且只有在用户被允许访问这些站中的任何一个(使用简单关系表)的情况下,用户才可以查看记录。
数据库中大约有200万个寄售单记录,客户抱怨加载包含20条记录的页面所需的时间太长。
不幸的是,在将最终查询传递到RDBMS(具体来说是Oracle 11g)之前,不可能对其进行优化,因为该系统具有复杂的体系结构和自制的ORM工具,并且最终查询在以下位置进行组装至少三个不同的地方负责收集要选择的字段,收集联接,添加UI中选择的条件,最后是出现此问题的原因-与权限相关的过滤器。
我不会说最终查询非常复杂;相反,它的本质很简单,但是却非常庞大。
恐怕在这种情况下,缓存解决方案将不会很有效,因为数据经常更改,并且缓存每分钟左右都会被覆盖。另外,由于个人权限的关系,每个用户都应该拥有自己的缓存,必须对其进行维护。
除了通常的建议-处理索引并尽可能优化每个子查询-还有其他众所周知的解决方案,用于基于复杂的权限规则过滤大量记录吗?
答案 0 :(得分:1)
只需两美分,因为我周围没有其他答案。
首先,您需要获取查询的执行计划。没有它,想知道可以改进什么并不容易。如果不是出于您的紧急程度,这听起来像是一个不错的挑战。
好吧,您说查询有17个左联接。这是否意味着查询中只有一个主表?如果是这样,那是我要优化的第一部分。关键方面是尽可能减少该表上的TABLE ACCESS BY ROWID
操作。典型的解决方案是添加量身定制的索引,以尽可能缩小该表上的INDEX RANGE SCAN
,从而减少堆的获取。
然后,在浏览其余[外部]表(大概使用NESTED LOOPS
)时,您可以尝试将其中一些条件具体化为可以使用的简单0/1标志,而不是整个条件。>
此外,如果您只需要20行,那么我希望它会很快...只要查询正确地进行管线化。如果您的情况花费的时间太长,那么情况可能并非如此。您是否按阻止流水线的某些特定条件进行排序/汇总/窗口显示?如果您只需要20行,则此条件可能是索引的最重要因素。
最后,您可以尝试使用“覆盖索引”来避免堆获取。这确实可以提高查询的性能,但是由于它们有缺点,因此我将保留它作为最后的选择。
嗯,再好的一个解决方案确实需要仔细看一下执行计划。如果您仍然是游戏,请将其发布,我可以看看。