जब आप बाइंड वैरिएबल का उपयोग करते हैं, तो Oracle को का उपयोग करने के लिए बाध्य किया जाता है। गतिशील विभाजन प्रूनिंग स्थिर विभाजन प्रूनिंग के बजाय . इसका परिणाम यह है कि Oracle को पार्स समय पर पता नहीं होता है कि कौन से पार्टिशन एक्सेस किए जाएंगे, क्योंकि यह आपके इनपुट वेरिएबल के आधार पर बदलता है।
इसका मतलब यह है कि शाब्दिक मूल्यों (बाध्य चर के बजाय) का उपयोग करते समय, हम जानते हैं कि आपके स्थानीय सूचकांक द्वारा कौन से विभाजन का उपयोग किया जाएगा। इसलिए count stopkey
विभाजन को छाँटने से पहले सूचकांक के आउटपुट पर लागू किया जा सकता है।
बाइंड चर का उपयोग करते समय, partition range iterator
आपको यह पता लगाना होगा कि आप किन विभाजनों तक पहुंच बना रहे हैं। इसके बाद यह सुनिश्चित करने के लिए एक जांच होती है कि बीच के संचालन में आपके पहले चर का वास्तव में कम मूल्य है, फिर दूसरा (filter
) दूसरी योजना में संचालन)।
इसे आसानी से पुन:प्रस्तुत किया जा सकता है, जैसा कि निम्नलिखित परीक्षण मामले से पता चलता है:
create table tab (
x date,
y integer,
filler varchar2(100)
) partition by range(x) (
partition p1 values less than (date'2013-01-01'),
partition p2 values less than (date'2013-02-01'),
partition p3 values less than (date'2013-03-01'),
partition p4 values less than (date'2013-04-01'),
partition p5 values less than (date'2013-05-01'),
partition p6 values less than (date'2013-06-01')
);
insert into tab (x, y)
select add_months(trunc(sysdate, 'y'), mod(rownum, 5)), rownum, dbms_random.string('x', 50)
from dual
connect by level <= 1000;
create index i on tab(x desc, y desc) local;
exec dbms_stats.gather_table_stats(user, 'tab', cascade => true);
explain plan for
SELECT * FROM (
SELECT rowid FROM tab
where x between date'2013-01-01' and date'2013-02-02'
and y between 50 and 100
order by x desc, y desc
)
where rownum <= 5;
SELECT * FROM table(dbms_xplan.display(null, null, 'BASIC +ROWS +PARTITION'));
--------------------------------------------------------------------
| Id | Operation | Name | Rows | Pstart| Pstop |
--------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | |
| 1 | COUNT STOPKEY | | | | |
| 2 | VIEW | | 1 | | |
| 3 | SORT ORDER BY STOPKEY | | 1 | | |
| 4 | PARTITION RANGE ITERATOR| | 1 | 2 | 3 |
| 5 | COUNT STOPKEY | | | | |
| 6 | INDEX RANGE SCAN | I | 1 | 2 | 3 |
--------------------------------------------------------------------
explain plan for
SELECT * FROM (
SELECT rowid FROM tab
where x between to_date(:st, 'dd/mm/yyyy') and to_date(:en, 'dd/mm/yyyy')
and y between :a and :b
order by x desc, y desc
)
where rownum <= 5;
SELECT * FROM table(dbms_xplan.display(null, null, 'BASIC +ROWS +PARTITION'));
---------------------------------------------------------------------
| Id | Operation | Name | Rows | Pstart| Pstop |
---------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | |
| 1 | COUNT STOPKEY | | | | |
| 2 | VIEW | | 1 | | |
| 3 | SORT ORDER BY STOPKEY | | 1 | | |
| 4 | FILTER | | | | |
| 5 | PARTITION RANGE ITERATOR| | 1 | KEY | KEY |
| 6 | INDEX RANGE SCAN | I | 1 | KEY | KEY |
---------------------------------------------------------------------
जैसा कि आपके उदाहरण में है, दूसरी क्वेरी केवल विभाजन को key
. पर फ़िल्टर कर सकती है पहले उदाहरण की तरह सटीक विभाजन के बजाय पार्स समय पर।
यह उन दुर्लभ मामलों में से एक है जहां शाब्दिक मूल्य बाइंड वैरिएबल की तुलना में बेहतर प्रदर्शन प्रदान कर सकते हैं। आपको जांच करनी चाहिए कि क्या यह आपके लिए एक संभावना है।
अंत में, आप कहते हैं कि आप प्रत्येक विभाजन से 20 पंक्तियाँ चाहते हैं। स्टैंड के रूप में आपकी क्वेरी ऐसा नहीं करेगी, यह आपके ऑर्डर के अनुसार आपको केवल पहली 20 पंक्तियाँ लौटाएगी। 20 पंक्तियों/विभाजन के लिए, आपको कुछ इस तरह करना होगा:
select rd from (
select rowid rd,
row_number() over (partition by trx_id order by create_ts desc) rn
from OUT_SMS
where TRX_ID between ? and ?
and CREATE_TS between ? and ?
order by CREATE_TS DESC, TRX_ID DESC
) where rn <= 20
अपडेट करें
आपको count stopkey
नहीं मिलने का कारण filter
के साथ क्या करना है "खराब" योजना की पंक्ति 4 में संचालन। आप इसे और अधिक स्पष्ट रूप से देख सकते हैं यदि आप ऊपर दिए गए उदाहरण को दोहराते हैं, लेकिन बिना किसी विभाजन के।
यह आपको निम्नलिखित योजनाएँ देता है:
----------------------------------------
| Id | Operation | Name |
----------------------------------------
| 0 | SELECT STATEMENT | |
|* 1 | COUNT STOPKEY | |
| 2 | VIEW | |
|* 3 | SORT ORDER BY STOPKEY| |
|* 4 | TABLE ACCESS FULL | TAB |
----------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM<=5)
3 - filter(ROWNUM<=5)
4 - filter("X">=TO_DATE(' 2013-01-01 00:00:00', 'syyyy-mm-dd
hh24:mi:ss') AND "X"<=TO_DATE(' 2013-02-02 00:00:00', 'syyyy-mm-dd
hh24:mi:ss') AND "Y">=50 AND "Y"<=100)
----------------------------------------
| Id | Operation | Name |
----------------------------------------
| 0 | SELECT STATEMENT | |
|* 1 | COUNT STOPKEY | |
| 2 | VIEW | |
|* 3 | SORT ORDER BY STOPKEY| |
|* 4 | FILTER | |
|* 5 | TABLE ACCESS FULL | TAB |
----------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM<=5)
3 - filter(ROWNUM<=5)
4 - filter(TO_NUMBER(:A)<=TO_NUMBER(:B) AND
TO_DATE(:ST,'dd/mm/yyyy')<=TO_DATE(:EN,'dd/mm/yyyy'))
5 - filter("Y">=TO_NUMBER(:A) AND "Y"<=TO_NUMBER(:B) AND
"X">=TO_DATE(:ST,'dd/mm/yyyy') AND "X"<=TO_DATE(:EN,'dd/mm/yyyy'))
जैसा कि आप देख सकते हैं, एक अतिरिक्त filter
है ऑपरेशन जब आप sort order by stopkey
. से पहले दिखने वाले बाइंड वैरिएबल का उपयोग करते हैं . यह सूचकांक तक पहुँचने के बाद होता है। यह जाँच कर रहा है कि चर के मान डेटा को वापस करने की अनुमति देंगे (आपके बीच में पहला चर वास्तव में दूसरे की तुलना में कम मान रखता है)। शाब्दिक का उपयोग करते समय यह आवश्यक नहीं है क्योंकि अनुकूलक पहले से ही जानता है कि 50 100 से कम है (इस मामले में)। यह नहीं जानता कि :a पार्स समय पर :b से कम है या नहीं।
वास्तव में ऐसा क्यों है मुझे नहीं पता। यह Oracle द्वारा जानबूझकर डिज़ाइन किया जा सकता है - स्टॉपकी जाँच करने का कोई मतलब नहीं है यदि चर के लिए निर्धारित मान शून्य पंक्तियों में परिणत होते हैं - या केवल एक निरीक्षण।