Oracle data paging optimization [closed] - performance

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
select * from (
select t_tmp_a.*, rownum t_tmp_id from (
select t.*, i.counts
from table1 t, (select id, count(id) counts from table2 group by id) i
where t.id=i.id and t.kindid in (0,1,3) order by t.id desc
) t_tmp_a where rownum <= 20) t_tmp_b where t_tmp_id >= 11;
table1 and table2 have more then 2 million data per table, when execute this query need 18s , before this query execute we should calculation total count need about 7s, so it spends more than 25s, any idea to optimiza it?

Pagination is usually a mechanism for displaying a result to a human being. No human being wants to read two million rows of data.
So if this query is indeed presenting rows to a real person then what you need to address is reducing the size of the whole result to something which is human-sized. So you need to apply additional filters in the database and return a focused result set. Not only will your users thank you, so will your network administrator.
On the other hand, if the intended recipient of this data deluge is a computer or other mechanical device then just give it the whole thing. Machines mostly don't care about pages, or if they do (spreadsheets, printers, etc) they have built-in sub-routines to handle pagination for us.
So that leaves us with the problem that your original query takes a long time to execute. Without any explain plan or statistics (how many rows in table1 fit the search criteria? how restricting are those values for kindid?) it is hard to solve this.
"kindid is a type which only have three choose(0,1,3)"
Fnord. If KINDID can only have three choices what is the point of using it in the WHERE clause?
In fact removing it from the WHERE clause may dramatically improve the performance of your query. Unless you have gathered histograms for that column Oracle will assume that in (0,1,3) is somehow going to restrict the result set; whereas that is only going to be true if the majority of rows have a NULL in that column. If that is the case it would be better to use kindid is not null.

Related

Coldfusion query and assign rows to a session [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I have come across a strange requirement, and really haven't a clue where to begin
We have an oracle database table that will be receiving data daily, and a CF application to interface with it
What they would like is for when a user logs in, to show x amount of rows from the table, and essentially "lock" the x amount of rows to that user, so when another user logs in, their x amount of rows are different, so noone is working concurrently on the same row
What i am guessing is a session write to a table, claiming the rows, but any thoughts would be more than welcome
There are a few ways to approach this problem. I will take a nibble here and tell you that you will need to get into Oracle database procedures and requires you to understand locking select for update clauses which you will immerse you in the nuances of sessions and how they work in oracle and you will call it using cfstoredproc.
There is another method. Now I have no idea about your coding environment or restrictions, nor do I know the user/system load considerations so this is just a suggestion. Adding a flag field to the table and make it a bit datatype or int...whatever. You are going to select them in a cfquery, then update the list of ids (setting bitItnFlag=1 ...or whatever you want to name this new field) which will mean 'this record is checked out'. You will still have the group of records in the first query which you will loop out to the end user to work with needing an update query setting them free by setting your bitIntFlag=0. They will be essentially locked. So another user will have to select where bitIntFlag=0 essentially skipping your locked group and setting their selected group (update them equal to 1). You can use cftransaction and two cfqueries like this.
<cftransaction action"begin">
<cfquery name="selectLock" datasource="#application.dsn#">
SELECT *
FROM (
SELECT *
FROM mytable
WHERE bitIntFlag = 0
ORDER BY
dbms_random.value
)
WHERE rownum <= 10
</cfquery>
<!---Now run your update--->
<cftry>
<cfquery name="updateLock" datasource="#application.dsn#">
UPDATE
myTable
SET
bitIntFlag = 1
WHERE
primaryKeyIDthing in #ValueList(selectLock.name)#
</cfquery>
<cfcatch type="database">
<cftransaction action="rollback"/>
</cfcatch>
<cftry>
<cftransaction action="commit"/>
</cftransaction>
<cfoutput query="selectLock">
#primaryKeyIDthing#<br>
</cfoutput>
(this code is untested but should get you started if you go down this route)
When you are done you update your records using cfquery and run your update sql and set the flag to zero to free up the records.
Again this is a simple work around that may or may not work for you. I don't know what kind of transactional intensity you are dealing with in your environment but sometimes making things simple can work!

Using temporary table in Stored procedure [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I have written stored procedure and it takes long time when i call it.
I use temporary table in 'SP'.
it can be reason ??
CREATE OR REPLACE PROCEDURE TEST_SP
IS
BEGIN
INSERT INTO MYTEMP_table (A, B )
( SELECT id AS CUSTOMER_NO,
ACC_NO AS ACCOUNT_NO
FROM myTable );
UPDATE MYTEMP_table
SET MYTEMP_table.A =
( SELECT MIN (BRH_DATE)
FROM CUSTOMER,)
UPDATE MYTEMP_table
SET MYTEMP_table.B =
( SELECT MIN (SUBSTR (ENTRY_DATE, 0, 8))
FROM INFO)
.......
MYTEMP_table is temporary table.
This code snippet looks woefully incomplete. Seems odd that you are filling the temp table with one query:
select id, acc_no from myTable
and then wiping out all columns with a single value:
UPDATE MYTEMP_table
SET MYTEMP_table.A =
( SELECT MIN (BRH_DATE)
FROM CUSTOMER,)
Your post is not clear, but hopefully you are using a global temporary table (Memory based) rather than a physical table meant for temporary storage.
Multiple writes to the same rows is a sure-fire way of slowing down the works (Much more-so in a physical table, but still slow either way). If possible, consider the following:
Use analytic functions or a more complex initial query to get all your writing done up front...
If you're not comfortable/familiar with running/reading explain plans, try running each SQL statement in a SQL Editor manually to assess their individual performance...

How does Inline view differ from Inline table in oracle?

Could anyone tell the difference between Inline view and Inline table ?
Explanation with SQL code might be good to understand the concept easily.
"this question has been asked to me in an interview."
We hear this a lot. The problem with these type of questions is you're asking the wrong people: you should have have the courage to say to your interviewer, "I'm sorry, I'm not familiar with the term 'inline table' could you please explain it?"
Instead you ask us, and the thing is, we don't know what the interview had in mind. I agree with Alex that the nearest thing to 'inline table' is the TABLE() function for querying nested table collections, but it's not a standard term.
I have been on the opposite side of the interviewing table many times. I always give credit to a candidate who asked me to clarify a question; I always mark down a candidate who blusters.
The world is struggling to optimize the database query, so am I. Well if I say I have something which can speed the application by factors to 80%, if used at right situations, what will you say...
Here I give you a problem, suppose you want to calculate the lowest and highest salary across the department with the name of employees with their respective manager.
One way to do it is to create a temp table which contain the aggregated salary for the employees.
create table tmp_emp_sal as select t.emp_id,max(t.sal) as maxsal,min(t.sal) as minsal,avg(t.sal) as avgsal from sal t group by t.emp_id
and then use it in query further.
select concat(e.last_nm, e.first_nm) as employee_name,concat(m.last_nm,m.first_nm) as manager_name,tt.maxsal,tt.minsal,tt.avgsal from emp e,emp m,dept d,tmp_test tt where e.dept_id = d.dept_id and s.emp_id = tt.emp_id and e.mgr_id = m.emp_id order by employee_name, manager_name
Now I will optimize the above code by merging the two DML and DDL operations in to a single DML query.
select concat(e.last_nm, e.first_nm) as employee_name,concat(m.last_nm, m.first_nm) as manager_name,tt.maxsal,tt.minsal,tt.avgsal from emp e,emp m, dept d,(select t.emp_id, max(t.sal) as maxsal, min(t.sal) as minsal, avg(t.sal) as avgsal from sal t group by emp_id) tt where e.dept_id = d.dept_id and s.emp_id = tt.emp_id and e.mgr_id = m.emp_id order by employee_name,manager_name
The above query saves user from the following shortcomings :-
Eliminates expensive DDL statements.
Eliminates a round trip to the database server.
Memory usage is much lighter because it only stores the final result rather than the intermediate steps as well.
So its preferable to use inline views in place of temp tables.

ORACLE db performance tuning

We are running into performance issue where I need some suggestions ( we are on Oracle 10g R2)
The situation is sth like this
1) It is a legacy system.
2) In some of the tables it holds data for the last 10 years ( means data was never deleted since the first version was rolled out). Now in most of the OLTP tables they are having around 30,000,000 - 40,000,000 rows.
3) Search operations on these tables is taking flat 5-6 minutes of time. ( a simple query like select count(0) from xxxxx where isActive=’Y’ takes around 6 minutes of time.) When we saw the explain plan we found that index scan is happening on isActive column.
4) We have suggested archive and purge of the old data which is not needed and team is working towards it. Even if we delete 5 years of data we are left with around 15,000,000 - 20,000,000 rows in the tables which itself is very huge, so we thought of having table portioning on these tables, but we found that the user can perform search of most of the columns of these tables from UI,so which will defeat the very purpose of table partitioning.
so what are the steps which need to be taken to improve this situation.
First of all: question why you are issuing the query select count(0) from xxxxx where isactive = 'Y' in the first place. Nine out of ten times it is a lazy way to check for existence of a record. If that's the case with you, just replace it with a query that select 1 row (rownum = 1 and a first_rows hint).
The number of rows you mention are nothing to be worried about. If your application doesn't perform well when number of rows grows, then your system is not designed to scale. I'd investigate all queries that take too long using a SQL*Trace or ASH and fix it.
By the way: nothing you mentioned justifies the term legacy, IMHO.
Regards,
Rob.
Just a few observations:
I'm guessing that the "isActive" column can have two values - 'Y' and 'N' (or perhaps 'Y', 'N', and NULL - although why in the name of Fred there wouldn't be a NOT NULL constraint on such a column escapes me). If this is the case an index on this column would have very poor selectivity and you might be better off without it. Try dropping the index and re-running your query.
#RobVanWijk's comment about use of SELECT COUNT(*) is excellent. ONLY ask for a row count if you really need to have the count; if you don't need the count, I've found it's faster to do a direct probe (SELECT whatever FROM wherever WHERE somefield = somevalue) with an apprpriate exception handler than it is to do a SELECT COUNT(*). In the case you cited, I think it would be better to do something like
BEGIN
SELECT IS_ACTIVE
INTO strIsActive
FROM MY_TABLE
WHERE IS_ACTIVE = 'Y';
bActive_records_found := TRUE;
EXCEPTION
WHEN NO_DATA_FOUND THEN
bActive_records_found := FALSE;
WHEN TOO_MANY_ROWS THEN
bActive_records_found := TRUE;
END;
As to partitioning - partitioning can be effective at reducing query times IF the field on which the table is partitioned is used in all queries. For example, if a table is partitioned on the TRANSACTION_DATE variable, then for the partitioning to make a difference all queries against this table would have to have a TRANSACTION_DATE test in the WHERE clause. Otherwise the database will have to search each partition to satisfy the query, so I doubt any improvements would be noted.
Share and enjoy.

Will "LIMIT 1" improve performance of a SELECT INTO query in plpgsql

The Postgres 9 docs state:
38.5.3. Executing a Query with a Single-Row Result
SELECT
select_expressions INTO [STRICT] target FROM
...; ....(doc'd othe details)...
then target will be set to the first row returned by the query....
Any result rows after the first row are discarded.
My question is: are the rows discarded or is there really an implicit LIMIT 1?
So, LIMIT 1 would not improve the performance of SELECT INTO returning many rows, or would it?
SELECT INTO reads exactly one or two rows (with the STRICT option). So LIMIT is useless.
From what I know using an ORDER BY and a LIMIT can often prevent shortening the query as it still needs to find all rows to perform the order by before it limits.
-Chris Shoemaker

Resources