I have to query a table with few millons of rows and I want to do it the most optimized.
Lets supose that we want to controll the access to a movie theater with multiples screening rooms and save it like this:
AccessRecord
(TicketId,
TicketCreationTimestamp,
TheaterId,
ShowId,
MovieId,
SeatId,
CheckInTimestamp)
To simplify, the 'Id' columns of the data type 'bigint' and the 'Timestamp' are 'datetime'. The tickets are sold at any time and the people access to the theater randomly. And the primary key (so also unique) is TicketId.
I want to get for each Movie and Theater and Show (time) the AccessRecord info of the first and last person who accessed to the theater to see a mov. If two checkins happen at the same time, i just need 1, any of them.
My solution would be to concatenate the PK and the grouped column in a subquery to get the row:
select
AccessRecord.*
from
AccessRecord
inner join(
select
MAX(CONVERT(nvarchar(25),CheckInTimestamp, 121) + CONVERT(varchar(25), TicketId)) as MaxKey,
MIN(CONVERT(nvarchar(25),CheckInTimestamp, 121) + CONVERT(varchar(25), TicketId)) as MinKey
from
AccessRecord
group by
MovieId,
TheaterId,
ShowId
) as MaxAccess
on CONVERT(nvarchar(25),CheckInTimestamp, 121) + CONVERT(varchar(25), TicketId) = MaxKey
or CONVERT(nvarchar(25),CheckInTimestamp, 121) + CONVERT(varchar(25), TicketId) = MinKey
The conversion 121 is to the cannonical expression of datatime resluting like this: aaaa-mm-dd hh:mi:ss.mmm(24h), so ordered as string data type it will give the same result as it is ordered as a datetime.
As you can see this join is not very optimized, any ideas?
Update with how I tested the different solutions:
I've tested all your answers in a real database with SQL Server 2008 R2 with a table over 3M rows to choose the right one.
If I get only the first or the last person who accessed:
- Joe Taras's solution lasts 10 secs.
- GarethD's solution lasts 21 secs.
If I do the same accessed but with an ordered result by the grouping columns:
- Joe Taras's solution lasts 10 secs.
- GarethD's solution lasts 46 secs.
If I get both (the first and the last) people who accessed with an ordered result:
- Joe Taras's (doing an union) solution lasts 19 secs.
- GarethD's solution lasts 49 secs.
The rest of the solutions (even mine) last more than 60 secs in the first test so I canceled it.