I have a query in the form:
select a, b, c, d, e, f, g, h,
row_number () over (partition by a, b order by c, d, e, f) as order
from table;
And it's performance is kind of terrible.
We have tried creating 2 indexes, the first for the partition by columns (a and b) and the second for the order by columns (c, d, e, f).
Using the explain plan we have found that indexes are not being used. Altough they are usefeul for other querys with a group by clause.
Any idea on how to refactor the query, or re-create the indexes so that they help with performance on this query?
Thanks in advance
To quote from a previous answer of mine:
The two most common reasons for a query not using indexes are:
It's quicker to do a full table scan.
Poor statistics.
In your case, you're selecting everything from the table so I'm guessing 1. is the main reason, in which case you're hosed.
You could try the index a, b, c, d, e, f, and I'm not saying that gathering statistics won't help. If you haven't I'd recommend doing it anyway:
begin
dbms_stats.gather_table_stats (
ownname => user,
tabname => 'MY_TABLE',
estimate_percent => 25,
method_opt => 'FOR ALL INDEXED COLUMNS',
cascade => TRUE );
end;
There's also the remote possibility that your table is massively fragmented. If so alter table my_table move and then gather statistics.
Related
I have a table with four fields: a, b, c and d.
I want a query like:
select distinct a, b from t;
The documentation suggests something like
(k/select my-table
(k/modifier "DISTINCT")
(k/fields :a :b))
But the generated SQL is like:
SELECT distinct a, b, c, d FROM my_table;
What I want is:
SELECT distinct a, b FROM my_table;
How do I restrict the distinct modifier to only two fields?
Experimenting with different modifier values (e.g. DISTINCT (a, b)) results in a mangled SQL Query.
Here's a complete example:
(k/defentity my-table (k/entity-fields :a :b :c :d))
(k/sql-only (k/select my-table (k/fields :a :b)
(k/modifier "DISTINCT")))
"SELECT DISTINCT `my-table`.`a`,
`my-table`.`b`,
`my-table`.`c`,
`my-table`.`d`,
`my-table`.`a`,
`my-table`.`b` FROM `my-table`"
The SQL keyword DISTINCT operates on the whole column in most (all?) databases, including MySQL and SQL Server. Therefore, in at least those databases, there is no way to use DISTINCT on a subset of fields.
A different query, possible like those suggested in SQL - 'DISTINCT' based on only some columns? might get you what you need.
I'm trying to do the following:
INSERT INTO MyTable(a, b, c)
SELECT a FROM source1
JOIN source2 ON ...
Where source2 contains columns B and C.
However Oracle doesn't seem to like this and is telling me "SQL Error: ORA-00947: not enough values".
Am I doing something wrong here? Is this syntax even possible? Or do I have to rewrite it as:
SELECT a, b, c FROM source1, source2 WHERE ....
Thanks!
Use as many identifiers in the SELECT clause as in the INSERT clause, as in:
INSERT INTO MyTable(a, b, c)
SELECT s1.a, s2.b, s2.c FROM source1 s1
JOIN source2 s2 ON ...
The select needs to return the same number of columns as you listed in the INSERT statement.
So: yes, you need to rewrite the query to SELECT a,b,c FROM ...
I have a query that looks like below and the tables A,T,S have around 1 million rows whereas P have more than 100 million rows. I've newly introduced the inline view "temp" into this query and it caused a drastic degradation in performance. The data retrieved for temp is hardly 50 rows and this inline query runs in a snap when executed alone.
The autotrace statistics show a huge increase in the number of "consistent gets" from a 6 digit number before introducing temp to a 9 digit number after adding this!! Also, more than 90% of LAST_CR_BUFFER_GETS are accounted for the "temp" view. If I extract the data from this view into a temporary table and use that table as part of the joins the performance is very good but that solution is not really feasible for me.
I know the question is very generalized but I'm wondering if there is anything trivially wrong in using this inline view.
Doesn't inline views give the same performance like having this data in a temporary table?
Is there any way I can hint Oracle to use this view in a effective manner and thus increasing performance.
select t.id,
a.date
from A a,
T t,
P p,
S s,
(select id
from S,
R
where s.id = r.id
and r.code = 10
r.code1 = 20
r.name = 'string1' ) temp
where ...cond1
...cond2
...cond2
s.id = temp.id
Best guess, based on my tuning experience is it's probably evaluating the inline view "temp" once per records matched from the result-set obtained by joining A, t, p, s.
The best solution here is to re-write it this way.
Keep in mind that the ORDERED hint assumes that you are providing the tables in the FROM clause in the order in which you want them to join.
I've listed temp and s first, cos that's the only join condition you have listed temp.id = s.id.
Also I'm assuming you have indexes on all the other columns that are part of the join criteria. Let me know if you have any more questions.
select /*+ ordered use_nl(a t p s) */
t.id, a.date
from (
select id
from S,
R
where s.id = r.id and r.code = 10 r.code1 = 20 r.name = 'string1'
) temp,
S s,
A a,
T t,
P p
where ...cond1 ...cond2 ...cond2 and s.id = temp.id
WITH TEMP AS
(select id
from S,
R
where s.id = r.id
and r.code = 10
r.code1 = 20
r.name = 'string1' )
select t.id,
a.date
from A a,
T t,
P p,
S
where ...cond1
...cond2
...cond2
s.id = temp.id;
try to run this query , and please provide the explain plan for this query
I have a query joining lots of fields. For some strange reason the index for one table is not being used at all( I use the index key clearly), instead it is doing a FULL table scan. I would like to force the index. We used to do optimizer hints in sybase. Is there a similar hint available in oracle?
For example, in sybase to join tables a, b, c and use myindex in table a, I would do :
SELECT a.*
FROM a(INDEX myindex),
b,
c
WHERE a.field1 = b.field1
AND b.field1 = c.field1
Question is how do I do this in oracle.
Thanks
Saro
Yes, there is a hint like that in Oracle. It looks something like this:
select /*+ index(a my_index) */ from a
I have two tables to join. TABLE_A (contains column 'a') and TABLE_BC (contains columns 'b' and 'c').
There is a condition on TABLE_BC. The two tables are joined by 'rowid'.
Something like:
SELECT a, b, c FROM main.TABLE_A INNER JOIN main.TABLE_BC WHERE (b > 10.0 AND c < 10.0) ON main.TABLE_A.rowid = main.TABLE_BC.rowid ORDER BY a;
Alternatively:
SELECT a, b, c FROM main.TABLE_A AS s1 INNER JOIN (SELECT rowid, b, c FROM main.TABLE_BC WHERE (b > 10.0 AND c < 10.0)) AS s2 ON s1.rowid = s2.rowid ORDER BY a;
I need to do this a couple of time with different TABLE_A, but TABLE_BC does not change... I could therefore speed things up by creating a temporary in-memory database (mem) for the constant part of the query.
CREATE TABLE mem.cache AS SELECT rowid, b, c FROM main.TABLE_BC WHERE (b > 10.0 AND c < 10.0);
followed by (many)
SELECT a, b, c FROM main.TABLE_A INNER JOIN mem.cache ON main.TABLE_A.rowid = mem.cache.rowid ORDER BY a;
I get the same result set from all the queries above, but the last option is by far the fastest one.
The problem is that I would like to avoid splitting the query into two parts. I would expect SQLite to do the same thing for me automatically (at least in the second scenario), but it does not seem to happen... Why is that?
Thanks.
SQLite is pretty light on optimization. The general rule of thumb: SmallTable Inner Join BigTable is faster than the reverse.
That being said I wonder if your first query would run faster in the following form:
SELECT a, b, c
FROM main.TABLE_A
INNER JOIN main.TABLE_BC ON main.TABLE_A.rowid = main.TABLE_BC.rowid
WHERE (b > 10.0 AND c < 10.0)
ORDER BY a;
Answer from the SQLite User Mailing List:
In short, because SQLite cannot read your mind.
To understand the answer compare speeds of executing one query (with
one TABLE_A) and creating an in-memory database, creating a table in
it and using that table in one query (with the same TABLE_A). I bet
the first option (straightforward query without in-memory database)
will be much faster. So SQLite selects the fastest way to execute your
query. It cannot predict what the future queries will be to understand
how to execute the whole set of queries faster. You can do that and
you should split your query in two parts.
Pavel