Reputation: 1186
Please kindly explain me whether these two give difference performances in execution. Both methods are giving nearly same results within nearly same time, but I need to know when it comes for selection of millions of data, what would be more suitable. Or are their execution logic inside same?
1)
CURSOR get_cost_ IS
SELECT EQUIP, COST
FROM EXIPMNT
WHERE mch_code = mch_code_
AND contract = contract_
AND CRE_DATE BETWEEN TO_DATE('01/01/' || year_, 'DD/MM/YYYY')
AND TO_DATE('01/01/' || year_, 'DD/MM/YYYY') + INTERVAL '1' YEAR;
BEGIN
FOR rec_ IN get_cost_ LOOP
IF (rec_. EQUIP = 'M') THEN
material_ := material_ + nvl(rec_.cost, 0);
ELSIF (rec_. EQUIP = 'P') THEN
personal_ := personal_ + nvl(rec_.cost, 0);
ELSIF (rec_. EQUIP = 'T') THEN
tool_facility_ := tool_facility_ + nvl(rec_.cost, 0);
ELSIF (rec_. EQUIP = 'X') THEN
expense_ := expense_ + nvl(rec_.cost, 0);
ELSIF (rec_. EQUIP = 'E') THEN
external_ := external_ + nvl(rec_.cost, 0);
ELSIF (rec_. EQUIP = 'D') THEN
direct_sales_ := direct_sales_ + nvl(rec_.cost, 0);
END IF;
NULL;
END LOOP;
2)
select sum(case when equip = 'M' then cost end) material_total,
sum(case when equip = 'P' then cost end) personal_total,
sum(case when equip = 'T' then cost end) tool_facility_total,
sum(case when equip = 'X' then cost end) expense_total,
sum(case when equip = 'E' then cost end) external_total,
sum(case when equip = 'D' then cost end) direct_sales_total,
sum(cost) total
from exipmnt
where mch_code = mch_code_
and contract = contract_
and cre_date >= TO_DATE('01/01/' || year_, 'DD/MM/YYYY')
and cre_date < TO_DATE('01/01/' || year_, 'DD/MM/YYYY') + INTERVAL '1' YEAR
and equip in ('M', 'P', 'T', 'X', 'E', 'D');
Upvotes: 0
Views: 61
Reputation: 36107
Hi... I'm not quite understandable, why first query is a bad practice.
Make a simple experiment, and you will see why it is a bad practice.
Make a very simple queries (without WHERE clause), one in SQL and the other in PL/SQL, against a table with a few hundred thousands rows, and compare how longthey take.
Both queriest just retrieve all rows from the table and calculate a result.
Below is what I did on my PC:
Create a test table
create table EXIPMNT as
select column_value as equip,
trunc(dbms_random.value(0,100)) as cost
from table(DBMSOUTPUT_LINESARRAY('M','P','T','X'))
cross join
all_objects
;
select count(*) from EXIPMNT;
COUNT(*)
----------
294852
An then the last query (SQL)
set timing on
select sum(case when equip = 'M' then cost end) material_total,
sum(case when equip = 'P' then cost end) personal_total,
sum(case when equip = 'T' then cost end) tool_facility_total,
sum(case when equip = 'X' then cost end) expense_total,
sum(case when equip = 'E' then cost end) external_total,
sum(case when equip = 'D' then cost end) direct_sales_total,
sum(cost) total
from exipmnt;
Elapsed: 00:00:00.078
and the first query (PL/SQL)
set timing on
DECLARE
CURSOR get_cost_ IS
SELECT EQUIP, COST
FROM EXIPMNT;
material_ number;
personal_ number;
tool_facility_ number;
expense_ number;
external_ number;
direct_sales_ number;
BEGIN
FOR rec_ IN get_cost_ LOOP
IF (rec_. EQUIP = 'M') THEN
material_ := material_ + nvl(rec_.cost, 0);
ELSIF (rec_. EQUIP = 'P') THEN
personal_ := personal_ + nvl(rec_.cost, 0);
ELSIF (rec_. EQUIP = 'T') THEN
tool_facility_ := tool_facility_ + nvl(rec_.cost, 0);
ELSIF (rec_. EQUIP = 'X') THEN
expense_ := expense_ + nvl(rec_.cost, 0);
ELSIF (rec_. EQUIP = 'E') THEN
external_ := external_ + nvl(rec_.cost, 0);
ELSIF (rec_. EQUIP = 'D') THEN
direct_sales_ := direct_sales_ + nvl(rec_.cost, 0);
END IF;
NULL;
END LOOP;
end;
/
anonymous block completed
Elapsed: 00:00:03.265
Now check results (elapsed time) - 3.265 sec. (PL/SQL) and 0.078 sec. (SQL)
3.265 / 0.078 = 41,85,
this means, that in this simple experiment PL/SQL is about 42 times slower than simple SQL.
That means the difference is 4200% !!!
Because of the above PL/SQL is perceived as a "bad practice".
Upvotes: 1
Reputation: 94913
You want to know what's better: PL/SQL or SQL for the task given.
PL/SQL is a programming language using SQL. So PL/SQL sents the query to the SQL machine and gets results that it reads record for record. This is a rather slow process. Okay, both the PL/SQL and the SQL engine are on the same machine, so there is not that much overhead, but still...
Your second approach shows that the task is easily solvable with one query. The optimizer will read the query and find the most appropriate way to execute it. Maybe there is an index helping look up the eqip code, so the task becomes very easy. Or the optimizer decides to execute this in several parallel tasks to speed up the process.
You see, there are many things possible for the DBMS when it executes SQL. Simply getting raw data and evaluate it from a programming language doesn't make use of these possibilities. So when you can execute the same task with SQL only, this is usually the way to go. (Though PL/SQL is a great language and can make complex tasks very readable, so even when you can write a query for a task you may still decide for PL/SQL for this reason.)
Upvotes: 1