Monday, March 19, 2012

Manually determine execution plan?

Hi- is it possible (and does it ever make sense), to manually determine a
query execution plan, instead of letting the optimizer do it. There are
certain times, when I think "well, I [think I] know that the best place to
start would be with choosing all matching rows from table a, because this
will narrow down the query most quickly, and because there is a perfect inde
x
available on table a..." And sometimes, what I think does not appear to be i
n
line with what the optimizer seems to think...
If it's possible and it makes sense, how does one do it?
ChrisLook up "hints" in Books Online. You can "guide" the optimizer through the
use of hints in the FROM clause.
There are plenty of details in Books Online.
You can declare which indexes to use, how to acquire locks, etc. However,
you need to be really careful there and add hints only if you think the
optimizer fails to select the most efficient execution plan for a diverse
selection of cases - e.g. if the optimizer fails to use the indexes on an
indexed view and performs data retrieval from the base tables, you could use
the NOEXPAND hint in the from clause.
This is a big issue, so read up on it in Books Online before drastically
affecting any production processes.
ML
http://milambda.blogspot.com/|||You know, I had looked at hints and thought it couldn't do what I wanted to
do; but looking again, I can see that I can do it exactly with "force order"
and "index =". Thanks a lot, I think this should make a major difference.
Chris
"ML" wrote:

> Look up "hints" in Books Online. You can "guide" the optimizer through the
> use of hints in the FROM clause.
> There are plenty of details in Books Online.
> You can declare which indexes to use, how to acquire locks, etc. However,
> you need to be really careful there and add hints only if you think the
> optimizer fails to select the most efficient execution plan for a diverse
> selection of cases - e.g. if the optimizer fails to use the indexes on an
> indexed view and performs data retrieval from the base tables, you could u
se
> the NOEXPAND hint in the from clause.
> This is a big issue, so read up on it in Books Online before drastically
> affecting any production processes.
>
> ML
> --
> http://milambda.blogspot.com/|||One more question re this; is there any way to specify in which order the
elements of the "where" clause are applied? I don't see anything like this.
Though I suppose maybe I could make a bunch of subqueries and then use the
FORCE ORDER'
Chris
"ML" wrote:

> Look up "hints" in Books Online. You can "guide" the optimizer through the
> use of hints in the FROM clause.
> There are plenty of details in Books Online.
> You can declare which indexes to use, how to acquire locks, etc. However,
> you need to be really careful there and add hints only if you think the
> optimizer fails to select the most efficient execution plan for a diverse
> selection of cases - e.g. if the optimizer fails to use the indexes on an
> indexed view and performs data retrieval from the base tables, you could u
se
> the NOEXPAND hint in the from clause.
> This is a big issue, so read up on it in Books Online before drastically
> affecting any production processes.
>
> ML
> --
> http://milambda.blogspot.com/|||AFAIK the optimizer is free to choose any order "he" sees fit as far as the
WHERE clause is concerned. I hope you're not using WHERE for joins...?
ML
http://milambda.blogspot.com/|||No there isn't. But depending on your intentions, the CASE expression
could achieve what you want.
Gert-Jan
querylous wrote:
> One more question re this; is there any way to specify in which order the
> elements of the "where" clause are applied? I don't see anything like this
.
> Though I suppose maybe I could make a bunch of subqueries and then use the
> FORCE ORDER'
> Chris
> "ML" wrote:
>|||How to use a case in this situation? Wouldn't this result in running a query
twice. Let's say I have table with a date and a value, and I want to find al
l
rows between date range x-y and values a-b. I know that there are very few
entries between dates x and y, but there are many rows with values a and b.
So, I want to make sure the query checks the date first, instead of the valu
e
(very simple example). How would I control this with a case?
"Gert-Jan Strik" wrote:

> No there isn't. But depending on your intentions, the CASE expression
> could achieve what you want.
> Gert-Jan
>
> querylous wrote:
>|||The query below will always check the date column first, and will only
check the value column if the data column is within range.
However, the query will probably not be able to use an index because of
this (complex) expression.
SELECT ...
FROM ...
WHERE CASE
WHEN my_date_column BETWEEN x AND y
THEN
CASE WHEN my_value_column BETWEEN a AND b
THEN 1
ELSE 0
END
ELSE 0
END = 1
Gert-Jan
querylous wrote:
> How to use a case in this situation? Wouldn't this result in running a que
ry
> twice. Let's say I have table with a date and a value, and I want to find
all
> rows between date range x-y and values a-b. I know that there are very few
> entries between dates x and y, but there are many rows with values a and b
.
> So, I want to make sure the query checks the date first, instead of the va
lue
> (very simple example). How would I control this with a case?
> "Gert-Jan Strik" wrote:
>|||Chris,
Assuming that the query conditions are straightfoward ranges that
indexes can be used for, the column statistics on the table will
give the optimizer enough information to make the best choice.
When the optimizer makes the wrong choice, there are
a lot of possibilities. Here are a few.
The query may have been autoparameterized. If it was first
run with ranges that made one query plan good, then run again
with changes only to the range endpoints, the query plan may
not be reevaluated. A compiled/cached plan from the earlier
execution will be used, and the query will not run efficiently.
This is a common occurrence. Search these groups for
"parameter sniffing" and "recompilation" for information.
It may not be the wrong choice. A selective index is not always
the best thing to use. If it's not a covering index, for example, using a
more selective index may incur other query processing costs (bookmark
operations, nonsequential disk access) that outweigh the selectivity.
It may be the wrong choice, but because of reasons the optimizer
is unable to evaluate (correlated columns or other questions of
the actual, not statistical, distribution of data).
Without seeing the actual query, the table and index definitions, an
idea of the data distribution, and the query plans (the optimizer's
plan and the better plan that exists), it's hard to say what might
be going on.
It's worth pointing out that in SQL Server 2005, you have
somewhat more control over this behavior. The OPTIMIZE
FOR option can be used to tell the optimizer to use statistics
for values other than the actual parameters in query ranges.
Here's an example of the same query with two different OPTIMIZE FOR
clauses, where you can see different plans:
declare @.from datetime
declare @.to datetime
set @.from = '19970101'
set @.to = '19970401'
select *
from Northwind..Orders
where OrderDate between @.from and @.to
and Freight between 10 and 20
option (optimize for (@.from='19970101', @.to='19980101'))
select *
from Northwind..Orders
where OrderDate between @.from and @.to
and Freight between 10 and 20
option (optimize for (@.from='19980101', @.to='19980101'))
Steve Kass
Drew University
querylous wrote:
>How to use a case in this situation? Wouldn't this result in running a quer
y
>twice. Let's say I have table with a date and a value, and I want to find a
ll
>rows between date range x-y and values a-b. I know that there are very few
>entries between dates x and y, but there are many rows with values a and b.
>So, I want to make sure the query checks the date first, instead of the val
ue
>(very simple example). How would I control this with a case?
>"Gert-Jan Strik" wrote:
>
>

No comments:

Post a Comment