Oracle
 sql >> डेटाबेस >  >> RDS >> Oracle

अपवादों का उपयोग करने की तुलना में धीमी गति से चयन करने से पहले SELECT COUNT(*) का उपयोग है?

यदि आप प्रश्न से सटीक प्रश्नों का उपयोग करते हैं तो पाठ्यक्रम का पहला संस्करण धीमा है क्योंकि इसे तालिका में सभी रिकॉर्डों की गणना करनी चाहिए जो मानदंडों को पूरा करते हैं।

इसे

. के रूप में लिखा जाना चाहिए
SELECT COUNT(*) INTO row_count FROM foo WHERE bar = 123 and rownum = 1;

या

select 1 into row_count from dual where exists (select 1 from foo where bar = 123);

क्योंकि रिकॉर्ड अस्तित्व की जांच करना आपके उद्देश्य के लिए पर्याप्त है।

बेशक, दोनों प्रकार इस बात की गारंटी नहीं देते कि कोई अन्य व्यक्ति foo . में कुछ नहीं बदलेगा दो बयानों के बीच, लेकिन यह कोई समस्या नहीं है यदि यह चेक अधिक जटिल परिदृश्य का हिस्सा है। ज़रा उस स्थिति के बारे में सोचें जब किसी ने foo.a . का मान बदल दिया हो var . में इसका मान चुनने के बाद कुछ कार्य करते समय जो चयनित var . को संदर्भित करता है मूल्य। इसलिए जटिल परिदृश्यों में अनुप्रयोग तर्क स्तर पर ऐसे समवर्ती मुद्दों को संभालना बेहतर होता है।
परमाणु संचालन करने के लिए एकल SQL कथन का उपयोग करना बेहतर होता है।

ऊपर दिए गए किसी भी प्रकार के लिए SQL और PL/SQL के बीच 2 संदर्भ स्विच की आवश्यकता होती है और 2 क्वेरीज़ का प्रदर्शन धीमा होता है, जब तालिका में पंक्ति मिलने पर नीचे वर्णित किसी भी प्रकार का प्रदर्शन धीमा होता है।

बिना किसी अपवाद के पंक्ति के अस्तित्व की जाँच करने के लिए अन्य प्रकार हैं:

select max(a), count(1) into var, row_count 
from foo 
where bar = 123 and rownum < 3;

अगर row_count =1 तो केवल एक पंक्ति मापदंड को पूरा करती है।

कभी-कभी यह केवल अस्तित्व की जांच करने के लिए पर्याप्त होता है क्योंकि foo . पर अद्वितीय बाधा होती है जो गारंटी देता है कि कोई डुप्लीकेट bar नहीं है foo . में मान . उदा. bar प्राथमिक कुंजी है।
ऐसे मामलों में क्वेरी को सरल बनाना संभव है:

select max(a) into var from foo where bar = 123;
if(var is not null) then 
  ...
end if;

या मानों को संसाधित करने के लिए कर्सर का उपयोग करें:

for cValueA in ( 
  select a from foo where bar = 123
) loop
  ...  
end loop;

अगला संस्करण लिंक से है , @user272735 द्वारा उनके उत्तर में प्रदान किया गया:

select 
  (select a from foo where bar = 123)
  into var 
from dual;

मेरे अनुभव से ज्यादातर मामलों में अपवाद ब्लॉक के बिना कोई भी संस्करण तेजी से अपवादों के साथ एक संस्करण है, लेकिन अगर ऐसे ब्लॉक के निष्पादन की संख्या कम है तो no_data_found को संभालने के साथ अपवाद ब्लॉक का उपयोग करना बेहतर है। और too_many_rows कोड पठनीयता में सुधार के लिए अपवाद।

अपवाद का उपयोग करने या उसका उपयोग न करने का चयन करने का सही बिंदु, एक प्रश्न पूछना है "क्या यह स्थिति आवेदन के लिए सामान्य है?"। यदि पंक्ति नहीं मिली और यह एक अपेक्षित स्थिति है जिसे संभाला जा सकता है (उदाहरण के लिए नई पंक्ति जोड़ें या किसी अन्य स्थान से डेटा लें और इसी तरह) अपवाद से बचने के लिए बेहतर है। यदि यह अप्रत्याशित है और स्थिति को ठीक करने का कोई तरीका नहीं है, तो त्रुटि संदेश को अनुकूलित करने के लिए अपवाद को पकड़ें, इसे इवेंट लॉग में लिखें और फिर से फेंक दें, या इसे बिल्कुल भी न पकड़ें।

प्रदर्शन की तुलना करने के लिए बस अपने सिस्टम पर एक साधारण टेस्ट केस बनाएं जिसमें दोनों वेरिएंट को कई बार कॉल किया जाए और तुलना करें। जिन मुद्दों पर पहले ध्यान दिया जाना चाहिए।

अपडेट करें

मैंने इस पृष्ठ से उदाहरण पुन:प्रस्तुत किया थोड़ा सुधार के साथ SQLFiddle साइट पर (link ).
परिणाम dual . से चयन करके उस प्रकार को साबित करते हैं सबसे अच्छा प्रदर्शन करता है:अधिकांश क्वेरी सफल होने पर थोड़ा ऊपर की ओर और लापता पंक्तियों की संख्या बढ़ने पर सबसे कम प्रदर्शन में गिरावट।
आश्चर्यजनक रूप से गिनती के साथ भिन्न () और सभी क्वेरी विफल होने पर दो प्रश्नों ने सबसे अच्छा परिणाम दिखाया।

| FNAME | LOOP_COUNT | ALL_FAILED | ALL_SUCCEED | variant name |
----------------------------------------------------------------
|    f1 |       2000 |       2.09 |        0.28 |  exception   |
|    f2 |       2000 |       0.31 |        0.38 |  cursor      |
|    f3 |       2000 |       0.26 |        0.27 |  max()       |
|    f4 |       2000 |       0.23 |        0.28 |  dual        |
|    f5 |       2000 |       0.22 |        0.58 |  count()     |

-- FNAME        - tested function name 
-- LOOP_COUNT   - number of loops in one test run
-- ALL_FAILED   - time in seconds if all tested rows missed from table
-- ALL_SUCCEED  - time in seconds if all tested rows found in table
-- variant name - short name of tested variant

नीचे परीक्षण वातावरण और परीक्षण स्क्रिप्ट के लिए एक सेटअप कोड है।

create table t_test(a, b)
as
select level,level from dual connect by level<=1e5
/
insert into t_test(a, b) select null, level from dual connect by level < 100
/

create unique index x_text on t_test(a)
/

create table timings(
  fname varchar2(10), 
  loop_count number, 
  exec_time number
)
/

create table params(pstart number, pend number)
/
-- loop bounds
insert into params(pstart, pend) values(1, 2000)
/

-- f1 - अपवाद हैंडलिंग

create or replace function f1(p in number) return number
as
  res number;
begin
  select b into res
  from t_test t
  where t.a=p and rownum = 1;
  return res;
exception when no_data_found then
  return null;
end;
/

-- f2 - कर्सर लूप

create or replace function f2(p in number) return number
as
  res number;
begin
  for rec in (select b from t_test t where t.a=p and rownum = 1) loop
    res:=rec.b;
  end loop;
  return res;
end;
/

-- f3 - अधिकतम ()

create or replace function f3(p in number) return number
as
  res number;
begin
  select max(b) into res
  from t_test t
  where t.a=p and rownum = 1;
  return res;
end;
/

-- f4 - दोहरे से चयन में फ़ील्ड के रूप में चुनें

create or replace function f4(p in number) return number
as
  res number;
begin
  select
    (select b from t_test t where t.a=p and rownum = 1)
    into res
  from dual;
  return res;
end;
/

-- f5 - चेक काउंट () फिर वैल्यू प्राप्त करें

create or replace function f5(p in number) return number
as
  res number;
  cnt number;
begin
  select count(*) into cnt
  from t_test t where t.a=p and rownum = 1;

  if(cnt = 1) then
    select b into res from t_test t where t.a=p;
  end if;

  return res;
end;
/

टेस्ट स्क्रिप्ट:

declare
  v       integer;
  v_start integer;
  v_end   integer;

  vStartTime number;

begin
  select pstart, pend into v_start, v_end from params;

  vStartTime := dbms_utility.get_cpu_time;

  for i in v_start .. v_end loop
    v:=f1(i);
  end loop;

  insert into timings(fname, loop_count, exec_time) 
    values ('f1', v_end-v_start+1, (dbms_utility.get_cpu_time - vStartTime)/100) ;
end;
/

declare
  v       integer;
  v_start integer;
  v_end   integer;

  vStartTime number;

begin
  select pstart, pend into v_start, v_end from params;

  vStartTime := dbms_utility.get_cpu_time;

  for i in v_start .. v_end loop
    v:=f2(i);
  end loop;

  insert into timings(fname, loop_count, exec_time) 
    values ('f2', v_end-v_start+1, (dbms_utility.get_cpu_time - vStartTime)/100) ;
end;
/

declare
  v       integer;
  v_start integer;
  v_end   integer;

  vStartTime number;

begin
  select pstart, pend into v_start, v_end from params;

  vStartTime := dbms_utility.get_cpu_time;

  for i in v_start .. v_end loop
    v:=f3(i);
  end loop;

  insert into timings(fname, loop_count, exec_time) 
    values ('f3', v_end-v_start+1, (dbms_utility.get_cpu_time - vStartTime)/100) ;
end;
/

declare
  v       integer;
  v_start integer;
  v_end   integer;

  vStartTime number;

begin
  select pstart, pend into v_start, v_end from params;

  vStartTime := dbms_utility.get_cpu_time;

  for i in v_start .. v_end loop
    v:=f4(i);
  end loop;

  insert into timings(fname, loop_count, exec_time) 
    values ('f4', v_end-v_start+1, (dbms_utility.get_cpu_time - vStartTime)/100) ;
end;
/

declare
  v       integer;
  v_start integer;
  v_end   integer;

  vStartTime number;

begin
  select pstart, pend into v_start, v_end from params;
  --v_end := v_start + trunc((v_end-v_start)*2/3);

  vStartTime := dbms_utility.get_cpu_time;

  for i in v_start .. v_end loop
    v:=f5(i);
  end loop;

  insert into timings(fname, loop_count, exec_time) 
    values ('f5', v_end-v_start+1, (dbms_utility.get_cpu_time - vStartTime)/100) ;
end;
/

select * from timings order by fname
/


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. किसी अन्य तालिका से तालिका अद्यतन करते समय प्रदर्शन समस्या

  2. पीएल/एसक्यूएल में स्ट्रिंग विभाजन

  3. एक इकाई संबंध आरेख में कार्डिनैलिटी को समझने की कोशिश कर रहे हैं?

  4. दिनांक तुलना असामान्य परिणाम देता है - SQL Oracle

  5. oracle में डिफ़ॉल्ट दिनांक स्वरूप बदलने के लिए Pl/Sql ट्रिगर