Reputation: 1044
i have a query like this:
select * from (
select * from TableX
where col1 % 2 = 0
) subquery
where col1 % 4 = 0
The actual subquery is more complicated. when i execute the subquery alone it returns maybe 200rows quickly, but when i execute the whole query, it takes too long to wait.
I know sql server takes some optimization here and merge the where
statement into the subquery, and produce the new execution plan which is not that efficient. Althought i can dive into the execution plan and analyze why, like index missing, statistics stale.
But i surely know that, my subquery which serves as a BaseTable will only return a small portion of data, so i want all further filtering or joining will only take place in these small portion of data.
My question is, can i force sql server to execute the subquery first, without caring about the outer where
statement? (btw, TempTable is my last option, CTE is not working)
Upvotes: 20
Views: 11409
Reputation: 4058
If you have a key column in your TableX you can use a Self Join:
select x1.*
from TableX x1
inner join (
select x.IdColumn
from TableX x
where x.Col1 % 2 = 0
) x2 on x1.IdColumn = x2.IdColumn
where x1.Col1 % 4 = 0
Sql server will have to execute the inner query before to match the second condition.
You could use also the TOP(MaxInt)
trick:
select *
from (
select top (9223372036854775807) *
from TableX
where Col1 % 2 = 0
) subquery
where Col1 % 4 = 0
It will force to get subquery before apply the outer WHERE
filter
Upvotes: 33
Reputation: 57
Have you tried:
select * from (
select * from TableX as inner
where inner.col1 % 2 = 0
) as subquery
where subquery.col1 % 4 = 0
I believe it has to execute the subquery first here because you're explicitly having the where condition on the aliased result of the subquery.
Upvotes: -2
Reputation: 1903
CREATE TABLE [dbo].[Performance](
[Id1] [int] NOT NULL,
[Id2] [int] NOT NULL,
[Id3] [int] NOT NULL,
[Description] [varchar](50) NOT NULL,
CONSTRAINT [PK_Performance] PRIMARY KEY CLUSTERED
(
[Id1] ASC,
[Id2] ASC,
[Id3] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
select count(*) from [Performance]
= 2.000.000
select
a.*
from
[Performance] a
inner join (
select Id1,Id2,Id3,Description from [Performance] where ( id1 % 2 = 0)
) b on ( a.id1 = b.id1 )
where
( b.Id3 % 3 = 0 )
Self join with derived table
Results returned pretty fast I would say (200.000 rows).
Upvotes: -2
Reputation: 3843
You can use cte for that:
with cte as(
select * from TableX where col1 % 2 = 0
)
select * from ( select * from cte ) subquery where col1 % 4 = 0
Upvotes: -6