如何使用绑定变量转换为实体化视图查询

问题描述

我的环境:

  • Azure IaaS上的Oracle Enterprise Edition 12.2
  • Linux Red Hat版本7
  • 内存:32GB
  • cpu:8个vcpu
  • “内存目标”设置为16GB。

让我解释一下这个问题。我通过Azure Kubernetes中的REST服务运行的大型查询遇到一些问题。该查询使用大量表,并且未设置绑定变量时需要花费大量时间。实际上,当通知绑定变量时,查询仅需1.5秒。我试图说服开发查询的团队强制告知参数,但是他们说需求是原样,并且不能受到挑战。

我通过创建一些不存在的索引来最大程度地改善了查询,甚至我运行了sql调整任务来收集更多细节。我甚至尝试根据Tuning Advisor的建议创建一个新的sql配置文件,但是它使查询变得更慢,因此最后我放弃了它。当没有绑定值的查询单独运行时,需要14秒才能完成。但是,当同一查询成为大规模压力测试的一部分(同时有10至15个威胁)时,某些进程会因超时而终止,因此查询达到60秒而没有完成。

我一直看到相同的等待事件:PGA内存操作(在这方面,我还尝试设置更多的PGA,甚至增加了隐藏参数_pga_max_size和{{1}的认值}。我也尝试使用手动工作区设置运行它,我禁用了_smm_max_size,但没有任何一项使查询运行得更快或更慢。

再次澄清一下:当查询没有将设置为特定值的变量绑定时,就会发生此问题。只有在这种情况下,我才会遇到问题。

我的最后一个想法是创建一个物化视图,并在提交时快速刷新。数据库上的DML活动很少,因此数据并发不会成为问题,因此我相信不会有太多的锁定。我读到,自11g以来,Oracle在提交方面的快速刷新已经有了很多改进。但是,我不知道该怎么解决。我应该使用整个查询来创建一个MVIEW还是将其拆分?

在这件事上,我想征求您的意见。或者即使您看到可以优化的内容。不要犹豫,要求任何澄清。我试图将执行计划添加到问题中,但是我达到了最大的字符限制。

非常感谢您的支持

查询如下:

pga_aggregated_limit

解决方法

因此,首先,要回答您的问题-无法通过绑定变量提前实现这一点。您将需要在没有任何绑定变量条件的情况下实现查询,并且在实现视图中提供足够的数据以针对该条件评估绑定变量。

也就是说,

CREATE MATERIALIZED VIEW mat1 AS
SELECT ... all the data,no bind variables ...

并在运行时:

SELECT ... FROM mat1 WHERE ... bind variable conditions ...

您的查询有很多联接。 refresh fast on commit的物化视图可能很困难。如果您具有Oracle 12.2,请查看实例化视图的ENABLE ON QUERY COMPUTATION功能。基本上,您会定期刷新(可能每天或每隔几个小时刷新一次,具体取决于数据的(不稳定)程度以及查询运行的时间),但是Oracle仍会通过补充(稍微陈旧)来保证实时,新鲜的结果。 )的实例化视图数据与实例化视图日志中的数据。

总而言之,我暂时还不会去具体化。相反,我将根据不为空的条件切换到动态构建和执行查询。实际上,您给Oracle优化器带来了很大的压力,该优化器基本上只有两个工具可以很好地完成此工作:“ NVL-OR扩展”和绑定绑定游标。

这两种方法都为Oracle提供了一种方法,该方法可以根据为绑定变量指定的值来制定不同的执行计划。它们是很好的功能,但我只是认为您的查询可能会使他们完全信任我。如果存在已证明的问题,那就尤其如此。

诚然,如果您动态地构建和执行查询,这很痛苦,那么您将通过提交一堆更小,更集中,更易于优化的查询,使CBO的工作更加轻松。

当我说动态构建查询时,我的意思是这样的:

IF p_param_3rd_party_list IS NULL THEN
  l_sql := l_sql || ' AND NVL(:23,''XXX'') IS NOT NULL';
  l_sql := l_sql || ' AND NVL(:24,''XXX'') IS NOT NULL';
ELSE 
  -- I'm not bothering to convert all the single quotes to double quotes.  Syntax won't 
  -- work,but you get the idea...
  l_sql := l_sql || ' AND (supplier.thirdPartyNumber IN
                         (    SELECT REGEXP_SUBSTR (NVL (:23,''),'[^,]+',1,LEVEL)
                                FROM DUAL
                          CONNECT BY REGEXP_SUBSTR (NVL (:24,LEVEL)
                                        IS NOT NULL))
END IF;

EXECUTE IMMEDIATE l_sql USING ... all your bind variables

至关重要的是,即使出于可伸缩性原因而动态构建查询,仍要使用绑定变量(如上所示)。

当绑定变量为NULL时添加的虚拟条件点很重要,因此最终查询具有相同顺序的相同绑定变量列表,而与实际给出的参数无关。这样,您可以使用一个EXECUTE IMMEDIATE...USING...命令来执行它。否则,这是一个巨大的痛苦。