تا قبل از نسخه 26ai، کوئری‌هایی که شامل bind variable بودند، نمی‌توانستند از قابلیت query rewrite با استفاده از materialized view (MV) بهره ببرند و اوراکل مجبور بود داده‌ها را مستقیماً از جدول‌های پایه بخواند، که باعث از دست رفتن مزایای کاراییِ داده‌های پیش‌تجمیع‌شده (pre-aggregated data) می‌شد.

از Oracle AI Database 26ai به بعد، این محدودیت حذف شده است و این بهبود به optimizer اجازه می‌دهد مقدار واقعی bind variable را در زمان اجرا بررسی کرده و تصمیم بگیرد که آیا کوئری می‌تواند با استفاده از MV بازنویسی شود یا خیر.

مقایسه رفتار در اوراکل 19c و 26ai

ایجاد Materialized View

SQL> CREATE MATERIALIZED VIEW vahid.mv_emp_dep
ENABLE QUERY REWRITE AS
SELECT department_id,
       COUNT(*) AS emp_count,
       SUM(salary) AS total_salary
FROM vahid.employees where department_id<100
GROUP BY department_id;

Materialized view created

این MV داده‌های تجمیع‌شدهٔ کارمندان را برای دپارتمان‌هایی با شناسهٔ کمتر از ۱۰۰ ذخیره کرده و برای query rewrite خودکار مناسب است.

بررسی Query rewrite در 19c

وقتی کوئری‌ای اجرا کنیم که کاملاً در دامنهٔ تعریف MV باشد (مثل department_id < 90)،اوراکل 19c آن را به‌درستی با MV بازنویسی می‌کند:

SQL> SELECT department_id,
       COUNT(*) AS emp_count,
       SUM(salary) AS total_salary
FROM vahid.employees where department_id<90
GROUP BY department_id;
Execution Plan
----------------------------------------------------------
Plan hash value: 3470845597
-------------------------------------------------------------------------------------------
| Id  | Operation                    | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |            |     8 |    80 |     2   (0)| 00:00:01 |
|*  1 |  MAT_VIEW REWRITE ACCESS FULL| MV_EMP_DEP |     8 |    80 |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("MV_EMP_DEP"."DEPARTMENT_ID"<90)

اما اگر شرط کوئری خارج از دامنهٔ MV باشد (مانند department_id > 90)، اوراکل مجبور می‌شود از جدول پایه بخواند.

SQL> SELECT department_id,
       COUNT(*) AS emp_count,
       SUM(salary) AS total_salary
FROM vahid.employees where department_id>90
GROUP BY department_id;
Execution Plan
----------------------------------------------------------
Plan hash value: 1192169904
--------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |     8 |   208 |     3  (34)| 00:00:01 |
|   1 |  HASH GROUP BY     |           |     8 |   208 |     3  (34)| 00:00:01 |
|*  2 |   TABLE ACCESS FULL| EMPLOYEES |     8 |   208 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter("DEPARTMENT_ID">90)

مشکل اصلی: Bind Variable

وقتی از bind variable استفاده کنیم:

variable depid number
exec :depid := 90;
SQL> SELECT department_id,
       COUNT(*) AS emp_count,
       SUM(salary) AS total_salary
FROM vahid.employees where department_id<:depid
GROUP BY department_id;
Execution Plan
----------------------------------------------------------
Plan hash value: 1192169904

--------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           |    22 |   572 |     3  (34)| 00:00:01 |
|   1 |  HASH GROUP BY     |           |    22 |   572 |     3  (34)| 00:00:01 |
|*  2 |   TABLE ACCESS FULL| EMPLOYEES |    22 |   572 |     2   (0)| 00:00:01 |
--------------------------------------------------------------------------------

حتی اگر مقدار bind variable (یعنی ۹۰) در دامنهٔ MV باشد، اوراکل 19c قادر به query rewrite نیست، زیرا optimizer در هنگام parsing مقدار depid: را نمی‌داند. به همین دلیل، از MV صرفنظر می شود.

 

بررسی Query rewrite در Oracle AI Database 26ai

در اوراکل 26ai این محدودیت از بین رفته و اگر مقدار bind variable در دامنهٔ MV قرار داشت، کوئری بازنویسی می شود.

برای کوئری دارای bind variable:

SQL> variable depid number
SQL> exec :depid:=90
PL/SQL procedure successfully completed.

SQL> SELECT department_id,
       COUNT(*) AS emp_count,
       SUM(salary) AS total_salary
FROM vahid.employees where department_id<:depid
GROUP BY department_id;
Execution Plan
----------------------------------------------------------
Plan hash value: 3470845597
-------------------------------------------------------------------------------------------
| Id  | Operation                    | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |            |     8 |    80 |     3   (0)| 00:00:01 |
|*  1 |  MAT_VIEW REWRITE ACCESS FULL| MV_EMP_DEP |     8 |    80 |     3   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("MV_EMP_DEP"."DEPARTMENT_ID"<90)

در اوراکل 26ai، مقدار bind در زمان اجرا بررسی شده و چون در محدودهٔ MV است (<100)، optimizer کوئری را با استفاده از MV بازنویسی می‌کند. Execution plan در متن اصلی نشان داده شده و تأیید می‌کند که از MAT_VIEW REWRITE ACCESS استفاده شده است.

Vahid Yousefzadeh

ارائه خدمات مشاوره ، پشتیبانی و نصب و راه اندازی پایگاه داده اوراکل در سراسر کشور...................... تلفن: 09128110897 ایمیل:[email protected]

دیدگاهتان را بنویسید لغو پاسخ