Oracle view performance - sql

I have a view that runs a fairly complex query on a large amount of data. When I run the the view for all data it takes a couple minutes, which is fine. My problem is when I am reducing the result set by either joining to another table with less rows or using a where clause with subquery it still takes the full 2 minutes to run. What I found is that if I specify the id as text in the where clause the query will return very fast. To illustrate what I mean:
Given the query below returns a single row with the result 1234:
select id from mytable where external_id = 1;
If I query my view for all rows it takes about 2 minutes to execute, which is expected
Select * from my_view ;
If I query my view using the following query it will still take the full 2 minutes to execute:
Select * from my_view v where v.id = (select id from mytable where external_id = 1);
But if I specify the ID right in the query it will return in less then a second
Select * from my_view v where v.id =1234;
Since both queries will always return the same result is their anyway I can instruct oracle to run the sub query first so that it can filter the view in the same manner as the second query? (Note: joining to mytable yields the same result. I choose to use a subquery in the example because I thought it was clearer).

I did not fully your question, but maybe the MO_MERGE will help you.

Related

Oracle - Inner query takes time

I have two queries:
select * from PRE_DETAIL_REPORT a where item = (select item from apple_skus);
select * from PRE_DETAIL_REPORT a where item IN ('100299122');
the table: APPLE_SKUS
only has one item: 100299122
When I run the first query, it takes 2 minutes to execute
When I run the second query, it takes 3 seconds to execute
What can be the reason?
you can rewrite it in this way:
select a.* from PRE_DETAIL_REPORT a
join apple_skus t on t.item = a.item;
Its the way a sql query syntax works
You have manual values for selection in your 2nd query but in the first case you have subquery specified so again a
FROM CLAUSE, N THEN SELECT so, Querying a table will take
more time than a hardcode value even when theres a single record
You could try EXISTS as it uses correlated subquery which would be much faster
Select * from table t1 where exists (select 1 from table
where
Item =t1.item)
It’s very likely that the difference is due to a different access to PRE_DETAIL_REPORT; and as mentioned earlier by someone, an explain plan (or SQL Monitor report) will tell you the answer.
But until you provide the diagnostic, this is just a guess…

Which of these queries are faster, when used with SQL Server?

I want to check whether a table contains a row or not. Which is faster?
IF EXISTS(SELECT * FROM TABLE)
or
IF EXISTS(SELECT TOP 1 * FROM TABLE)
There is no difference between the queries!
The columns in the select don't get evaluated.
If you recall Logical Query processing, the from clause is executed first. The select clause is executed in the last step (actually Order By is, but that is a cosmetic thing).
So when the from clause gets executed, there are rows returned, regardless of the column names.
You have to add columnnames because otherwise you get syntax errors
IF EXISTS(SELECT 1 FROM TABLE)
is faster
there are some more suggestions
IF EXISTS(SELECT null FROM TABLE)
Obviously SELECT TOP 1 * FROM TABLE is faster.
since the index scan is reduced to one,number of rows return is one and
the estimated operation cost is also much less.
but if there is only on row in the table both the queries will show same operation cost.
SELECT *
FROM (SELECT top 1 *
FROM ms_data) temp
SELECT TOP 1 *
FROM ms_data
both the above queries have same operation cost.

Assistance with SQL statement

I'm using sql-server 2005 and ASP.NET with C#.
I have Users table with
userId(int),
userGender(tinyint),
userAge(tinyint),
userCity(tinyint)
(simplified version of course)
I need to select always two fit to userID I pass to query users of opposite gender, in age range of -5 to +10 years and from the same city.
Important fact is it always must be two, so I created condition if ##rowcount<2 re-select without age and city filters.
Now the problem is that I sometimes have two returned result sets because I use first ##rowcount on a table. If I run the query.
Will it be a problem to use the DataReader object to read from always second result set? Is there any other way to check how many results were selected without performing select with results?
Can you simplify it by using SELECT TOP 2 ?
Update: I would perform both selects all the time, union the results, and then select from them based on an order (using SELECT TOP 2) as the union may have added more than two. Its important that this next select selects the rows in order of importance, ie it prefers rows from your first select.
Alternatively, have the reader logic read the next result-set if there is one and leave the SQL alone.
To avoid getting two separate result sets you can do your first SELECT into a table variable and then do your ##ROWCOUNT check. If >= 2 then just select from the table variable on its own otherwise select the results of the table variable UNION ALLed with the results of the second query.
Edit: There is a slight overhead to using table variables so you'd need to balance whether this was cheaper than Adam's suggestion just to perform the 'UNION' as a matter of routine by looking at the execution stats for both approaches
SET STATISTICS IO ON
Would something along the following lines be of use...
SELECT *
FROM (SELECT 1 AS prio, *
FROM my_table M1 JOIN my_table M2
WHERE M1.userID = supplied_user_id AND
M1.userGender <> M2.userGender AND
M1.userAge - 5 >= M2.userAge AND
M1.userAge + 15 <= M2.userAge AND
M1.userCity = M2.userCity
LIMIT TO 2 ROWS
UNION
SELECT 2 AS prio, *
FROM my_table M1 JOIN my_table M2
WHERE M1.userID = supplied_user_id AND
M1.userGender <> M2.userGender
LIMIT TO 2 ROWS)
ORDER BY prio
LIMIT TO 2 ROWS;
I haven't tried it as I have no SQL Server and there may be dialect issues.

Separate Query for Count

I am trying to get my query to grab multiple rows while returning the maximum count of that query.
My query:
SELECT *, COUNT(*) as Max FROM tableA LIMIT 0 , 30
However, it is only outputting 1 record.
I would like to return multiple record as it was the following query:
SELECT * FROM tableA LIMIT 0 , 30
Do I have to use separate queries?
Use separate queries.
It's two separate pieces of information with different structures. One is a row set, the other is a single value. Trying to return both these pieces of information in one query, while possible, is not a good idea.
Well, you can use a single query with the SQL_CALC_FOUND_ROWS function in it, with the use of LIMIT as well. So, while you run the first query through mysql_query(), you can then also run another query as:
mysql_query("SELECT FOUND_ROWS()");
which will return you the number of total rows found through that query (no matter you use the LIMIT or not, SELECT FOUND_ROWS() will give you the result count without the LIMIT mentioned in your query).
Following is a sample query:
SELECT SQL_CALC_FOUND_ROWS * FROM tbl_abc
Thanks

SQL - Use results of a query as basis for two other queries in one statement

I'm doing a probability calculation. I have a query to calculate the total number of times an event occurs. From these events, I want to get the number of times a sub-event occurs. The query to get the total events is 25 lines long and I don't want to just copy + paste it twice.
I want to do two things to this query: calculate the number of rows in it, and calculate the number of rows in the result of a query on this query. Right now, the only way I can think of doing that is this (replace #total# with the complicated query to get all rows, and #conditions# with the less-complicated conditions that rows, from #total#, must have to match the sub-event):
SELECT (SELECT COUNT(*) FROM (#total#) AS t1 WHERE #conditions#) AS suboccurs,
COUNT(*) AS totaloccurs FROM (#total#) as t2
As you notice, #total# is repeated twice. Is there any way around this? Is there a better way to do what I'm trying to do?
To re-emphasize: #conditions# does depend on what #total# returns (it does stuff like t1.foo = bar).
Some final notes: #total# by itself takes ~250ms. This more complicated query takes ~300ms, so postgres is likely doing some optimization, itself. Still, the query looks terribly ugly with #total# literally pasted in twice.
If your sql supports subquery factoring, then rewriting it using the WITH statement is an option. It allows subqueries to be used more than once. With will create them as either an inline-view or a temporary table in Oracle.
Here is a contrived example.
WITH
x AS
(
SELECT this
FROM THERE
WHERE something is true
),
y AS
(
SELECT this-other-thing
FROM somewhereelse
WHERE something else is true
),
z AS
(
select count(*) k
FROM X
)
SELECT z.k, y.*, x.*
FROM x,y, z
WHERE X.abc = Y.abc
SELECT COUNT(*) as totaloccurs, COUNT(#conditions#) as suboccurs
FROM (#total# as t1)
Put the reused sub-query into a temp table, then select what you need from the temp table.
#EvilTeach:
I've not seen the "with" (probably not implemented in Sybase :-(). I like it: does what you need in one chunk then goes away, with even less cruft than temp tables. Cool.