A
A
Alexeytur2022-01-12 04:06:24
SQL query optimization
Alexeytur, 2022-01-12 04:06:24

Why is subquery execution slower?

Why is running a query as a subquery slower than running it sequentially the same number of times?

select top 1 login from SiemensLicUsage 
  where CONVERT(DATE,SiemensLicUsage.logDateTime)=DATEADD(DAY,-1,CONVERT(DATE, GETDATE()))
    and SiemensLicUsage.licId='cam_base' and SiemensLicUsage.filename='109012981';

The request is completed quickly.
But if you run it as a subquery for each date in the given date range:
DECLARE @StartDate DATE = DATEADD(DAY,-10,CONVERT(DATE,GETDATE()))
  , @EndDate DATE = CONVERT(DATE,GETDATE())
select dt,
(
  select top 1 login from SiemensLicUsage where SiemensLicUsage.licId='cam_base' and 
  SiemensLicUsage.filename='109012981' and CONVERT(DATE,SiemensLicUsage.logDateTime)=CONVERT(DATE, dt)
) LicUsageCount 
from
-- Генерация диапазона дат между заданными значениями------------------
(
  SELECT  DATEADD(DAY, nbr - 1, @StartDate) dt	
  FROM    ( SELECT    ROW_NUMBER() OVER ( ORDER BY c.object_id ) AS nbr
        FROM      sys.columns c
      ) nbrs
  WHERE   nbr - 1 <= DATEDIFF(DAY, @StartDate, @EndDate)
) dates
------------------------------------------------------------------------
order by dt desc;

Runs for 5 seconds even though there are only 11 dates in the range.
I try to execute this subquery sequentially for the same 11 dates:
spoiler

select top 1 login from SiemensLicUsage where CONVERT(DATE,SiemensLicUsage.logDateTime)=CONVERT(DATE, GETDATE())
and SiemensLicUsage.licId='cam_base' and SiemensLicUsage.filename='109012981';  
select top 1 login from SiemensLicUsage where CONVERT(DATE,SiemensLicUsage.logDateTime)=DATEADD(DAY,-1,CONVERT(DATE, GETDATE()))
and SiemensLicUsage.licId='cam_base' and SiemensLicUsage.filename='109012981';
select top 1 login from SiemensLicUsage where CONVERT(DATE,SiemensLicUsage.logDateTime)=DATEADD(DAY,-2,CONVERT(DATE, GETDATE()))
and SiemensLicUsage.licId='cam_base' and SiemensLicUsage.filename='109012981';
select top 1 login from SiemensLicUsage where CONVERT(DATE,SiemensLicUsage.logDateTime)=DATEADD(DAY,-3,CONVERT(DATE, GETDATE()))
and SiemensLicUsage.licId='cam_base' and SiemensLicUsage.filename='109012981';
select top 1 login from SiemensLicUsage where CONVERT(DATE,SiemensLicUsage.logDateTime)=DATEADD(DAY,-4,CONVERT(DATE, GETDATE()))
and SiemensLicUsage.licId='cam_base' and SiemensLicUsage.filename='109012981';
select top 1 login from SiemensLicUsage where CONVERT(DATE,SiemensLicUsage.logDateTime)=DATEADD(DAY,-5,CONVERT(DATE, GETDATE()))
and SiemensLicUsage.licId='cam_base' and SiemensLicUsage.filename='109012981';
select top 1 login from SiemensLicUsage where CONVERT(DATE,SiemensLicUsage.logDateTime)=DATEADD(DAY,-6,CONVERT(DATE, GETDATE()))
and SiemensLicUsage.licId='cam_base' and SiemensLicUsage.filename='109012981';
select top 1 login from SiemensLicUsage where CONVERT(DATE,SiemensLicUsage.logDateTime)=DATEADD(DAY,-7,CONVERT(DATE, GETDATE()))
and SiemensLicUsage.licId='cam_base' and SiemensLicUsage.filename='109012981';
select top 1 login from SiemensLicUsage where CONVERT(DATE,SiemensLicUsage.logDateTime)=DATEADD(DAY,-8,CONVERT(DATE, GETDATE()))
and SiemensLicUsage.licId='cam_base' and SiemensLicUsage.filename='109012981';
select top 1 login from SiemensLicUsage where CONVERT(DATE,SiemensLicUsage.logDateTime)=DATEADD(DAY,-9,CONVERT(DATE, GETDATE()))
and SiemensLicUsage.licId='cam_base' and SiemensLicUsage.filename='109012981';
select top 1 login from SiemensLicUsage where CONVERT(DATE,SiemensLicUsage.logDateTime)=DATEADD(DAY,-10,CONVERT(DATE, GETDATE()))
and SiemensLicUsage.licId='cam_base' and SiemensLicUsage.filename='109012981';


Runs 2 kopecks of a second.
The array of dates in the future can be very large.
Generating an array of dates without a subquery is also fast.
Tried to take out generation of an array of dates in CTE and in the temporary table, the same result.
Version of SQL Server 2008 R2.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
K
Konstantin Tsvetkov, 2022-01-12
@Alexeytur

Of course, you need to look at the intended and actual query execution plan.
But try adding ORDER BYby clustered index. Or is there an index on login?
No subqueries andSELECT TOP

DECLARE @StartDate DATE = DATEADD(DAY,-10,CONVERT(DATE,GETDATE())), 
        @EndDate DATE = CONVERT(DATE,GETDATE())
SELECT CONVERT(DATE, logDateTime), [login]
  FROM SiemensLicUsage
  WHERE (licId = 'cam_base') AND ([filename] = '109012981')
      AND CONVERT(DATE, logDateTime) BETWEEN @StartDate AND @EndDate
  GROUP BY CONVERT(DATE, logDateTime), [login]

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question