Here's an oddball. My software has the following query:select A.fldA, A.fldB from tableA A where A.fldKey IN( select AA.fldKey from tableA AA inner join tableB B ON AA.fldKey = B.fldKey inner join tableC C ON B.fldChild = C.fldChild)OR A.fldKey in( select AAA.fldKey from tableA AAA inner join tableX X ON AAA.fldKey = X.fldKey inner join tableC C ON X.fldChild = C.fldChild)
The app was hanging and when I checked statistics I found that tableB was being read 4 million times. The table contains about 100K worth of data. As a test I changed the query to read like this:select A.fldA, A.fldB from tableA A where A.fldKey IN( select AA.fldKey from tableA AA inner join tableB B ON AA.fldKey = B.fldKey inner join tableC C ON B.fldChild = C.fldChild)OR A.fldKey = 7
I got the same results. I know how to change the query so this doesn't happen but am curious as to why the DB is reading the table so many times. It seems that the optimizer sees that the correlated sub query can be treated as an inner join. Then when you add the additional conditional (I like how that sounds) it checks the condition against every row and subsequently performs a join for every row.Here is a testing script that shows what I mean:set statistics io OFFset nocount onCREATE TABLE #foo ( fldID int identity(1, 1), fldNum int not null)-- Get a few records startedinsert into #foo(fldNum) select 1 as X union all select 1 as X union all select 1 as X union all select 1 as X union all select 1 as X union all select 1 as X union all select 1 as X while (select count(fldID) from #foo) < 100000 insert into #foo(fldNum) select fldID from #fooselect count(fldID) from #fooset statistics io ON-- Get statistics on sub queryselect top 500 fldID from #foo-- Results Table #foo Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0.-- Get statistics on the main query and the sub queryselect A.fldID from #foo A where A.fldID IN( select top 500 B.fldID from #foo B)-- Results Table #foo Scan count 2, logical reads 256, physical reads 0, read-ahead reads 0.-- Get statistics on the second conditionselect A.fldID from #foo A where A.fldID = 1-- Results Table #foo Scan count 1, logical reads 254, physical reads 0, read-ahead reads 0.-- Get statistics on the whole thingselect A.fldID from #foo A where A.fldID IN( select top 500 B.fldID from #foo B) OR A.fldID = 1-- Results Table #foo Scan count 3, logical reads 256, physical reads 0, read-ahead reads 0.-- Table 'Worktable'. Scan count 498, logical reads 997, physical reads 0, read-ahead reads 0.-- Table 'Worktable'. Scan count 500, logical reads 1001, physical reads 0, read-ahead reads 0.-- Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0.
God Bless