2009-07-02 4 views
6

यह एक ही सबक्वायरी का उपयोग करके तीन अलग-अलग चयन है। मैं फिर से उप क्वेरी करने के बजाय subquery परिणाम का उपयोग कैसे कर सकता हूं।ऑरैकल में एकाधिक चयन में एक ही सबक्वायरी से कैसे बचें?

SELECT * 
FROM Address 
WHERE address_key IN 
     (
     SELECT address_key 
     FROM person_address 
     WHERE peson_key IN (person_list) 
     ); -- person_list := '1,2,3,4' 

SELECT * 
FROM Phone 
WHERE phone_key IN 
     (
     SELECT address_key 
     FROM person_address 
     WHERE peson_key IN (person_list) 
     ); 

SELECT * 
FROM Email 
WHERE address_key IN 
     (
     SELECT address_key 
     FROM person_address 
     WHERE peson_key IN (person_list) 
     ); 

उत्तर

6

आपने इस क्वेरी के लिए एक materialized दृश्य बना सकते हैं:

CREATE MATERIALIZED VIEW v_address 
REFRESH FORCE ON COMMIT 
AS 
SELECT address_key 
FROM person_address 
WHERE person_key IN (person_list) 

, या अस्थायी तालिका बनाने और इसे पॉप्युलेट:

CREATE GLOBAL TEMPORARY TABLE tt_address (VARCHAR2(50)); 

INSERT 
INTO tt_address 
SELECT address_key 
FROM person_address 
WHERE person_key IN (person_list) 

, लेकिन, वास्तव में, यदि आप सूचकांक अपने person_key, सबक्वायरी का पुन: उपयोग करना ठीक है।

चूंकि आपके पास 3 अलग-अलग प्रश्न हैं, तो आपको अपने मूल्यों को एक तरफ या दूसरे के लिए दृश्यमान होने की आवश्यकता है।

इसका मतलब है कि आपको इन मानों को कहीं और स्टोर करने की आवश्यकता है, चाहे यह स्मृति, अस्थायी टेबल स्पेस या स्थायी टेबलस्पेस हो।

लेकिन आपके द्वारा आवश्यक मूल्यों को पहले ही person_address में संग्रहीत किया गया है, आपको केवल उन्हें लाने की आवश्यकता है।

सबक्वेरी 3 बार का उपयोग करते हुए मेज से address_key लाने के लिए ROWID लुकअप person_key और 12 मेज पर सूचकांक से ROWID के लाने के लिए 12 सूचकांक स्कैन शामिल होगी। तो शायद अधिकतर HASH TABLE उनके ऊपर बनाया जाएगा।

यह माइक्रोसॉन्ड का मामला है।

बेशक, अस्थायी तालिका या एक materialized दृश्य एक छोटे से अधिक कुशल होगा, लेकिन 50 करने के लिए 100 माइक्रोसेकंड से सबक्वेरी समय बदल रहा है, यह शायद ही लायक है बशर्ते कि मुख्य प्रश्नों मिनट लग सकते हैं।

+0

+1 या जीटीटी विचार - विशेष रूप से अगर इसे पॉप्युलेट करने के लिए तर्क अधिक जटिल या उदाहरण के मुकाबले समय लेने वाला है। –

6

क्लॉज के साथ उपयोग करें। मैंने आपकी सटीक उदाहरण समस्या को फिर से नहीं बनाया है, लेकिन किसी भी संख्या में बार-बार उप-प्रश्नों को बिना खंड में रखा जा सकता है और फिर क्वेरी में संदर्भित किया जा सकता है।

WITH address_keys as (
     SELECT address_key 
     FROM person_address 
     WHERE peson_key IN (person_list) 
     ) 
Select * from table1, table2, address_keys 
where table1.address_key = address_keys.address_key 
and table2.address_key = address_keys.address_key 
+0

जैसा कि मैं चाहता हूं तीन परिणाम सेट वापस नहीं करता है। खंड के साथ बनाए गए दृश्य का उपयोग केवल एक क्वेरी में एकाधिक नहीं किया जा सकता है। मुझे कुछ याद आ रहा है। –

+0

मुझे लगता है कि ब्रायन का मुद्दा तीन प्रश्नों को चलाने के लिए नहीं है - यूनियन द्वारा एक प्रश्न को एक साथ चलाएं। यह भी इस तरह से अधिक कुशल होगा। –

+0

बेशक, यदि तीन परिणाम सेटों में जंगली रूप से भिन्न पैटर्न हैं, तो शायद यह मदद नहीं करेगा :) –

4

सबसे पहले मुझे लगता है कि ज्यादातर मामलों में इस अनुकूलन महत्वपूर्ण सुधार नहीं लाती (पहली क्वेरी के बाद PERSON_ADDRESS का डेटा ब्लॉक ज्यादातर बफर कैश में कैश की जाएगी और इसलिए HDD से पढ़ा नहीं)।

हालांकि केस केस या किसी भी कारण से: आपको दोहराने वाले क्वेरी परिणामों को कैश करने और बाद में उन्हें 3 चयनों में पुन: उपयोग करने की आवश्यकता है। यह एक (अस्थायी) तालिका या एमवी या एक plsql संरचना varray द्वारा हासिल किया जा सकता है।

पहले दो विकल्प क्वास्नोई को उनके उत्तर में शामिल करते हैं, इसलिए मैं उनका उल्लेख नहीं करूंगा। तीसरे व्यक्ति को अग्रिम पंक्तियों की अधिकतम गणना करने में हानि होती है (और मुझे नहीं पता कि क्या होता है जब आप 1 एम या 1 जी वस्तुओं के ऊपरी बाउंड के साथ एक varray घोषित करते हैं, भले ही आपको केवल 1k की आवश्यकता हो)।

--creating db object to hold the data - maximum of 1000 items allowed. 
--I assume that key is number(10,0). 
create type t_address_keys is varray (1000) of number (10,0); 

declare 
    la_address_keys t_address_keys; --declare cache variable 
begin 

--cache keys 
SELECT address_key 
bulk collect into la_address_keys 
     FROM person_address 
     WHERE peson_key IN (person_list); 

SELECT * 
into ... 
FROM Address 
WHERE address_key IN table(la_address_keys); 

SELECT * 
into ... 
FROM Phone 
WHERE address_key IN table(la_address_keys); 

SELECT * 
into ... 
FROM email 
WHERE address_key IN table(la_address_keys); 

end; 
/
संबंधित मुद्दे