Reputation: 61469
I am working with SQL server 2008
on query that looks for users within certain distance from central point that is moving - which means I am constantly hitting database (new results need to be added to the existing set and ones out of distance to be removed) and every millisecond saved is of value.
ATM we are using following query (Id's are used cause they are indexed ATM and good when trying for speed):
declare @lat int = 500,
@lon int = 700
SELECT @lat, @lon, id, journeyid, ((ACOS(SIN(@lat * PI() / 180) * SIN([Id] * PI() / 180) +
COS(@lat * PI() / 180) * COS([Id] * PI() / 180) * COS((@lon - [JourneyId]) *
PI() / 180)) * 180 / PI()) * 60 * 1.1515) as dist
FROM [OnlineLegal_dev1].[dbo].[Customer]
group by [Id], [JourneyId], ((ACOS(SIN(@lat * PI() / 180) * SIN([Id] * PI() / 180) +
COS(@lat * PI() / 180) * COS([Id] * PI() / 180) * COS((@lon - [JourneyId]) *
PI() / 180)) * 180 / PI()) * 60 * 1.1515)
HAVING ((ACOS(SIN(@lat * PI() / 180) * SIN([Id] * PI() / 180) +
COS(@lat * PI() / 180) * COS([Id] * PI() / 180) * COS((@lon - [JourneyId]) *
PI() / 180)) * 180 / PI()) * 60 * 1.1515)<=10000
ORDER BY ((ACOS(SIN(@lat * PI() / 180) * SIN([Id] * PI() / 180) +
COS(@lat * PI() / 180) * COS([Id] * PI() / 180) * COS((@lon - [JourneyId]) *
PI() / 180)) * 180 / PI()) * 60 * 1.1515) ASC
Current speed to select top 1k records is 00:00:00.097
How could I optimize this further for speed?
Upvotes: 0
Views: 72
Reputation: 112602
You could store the pre-calculated values
SIN([Id] * PI() / 180)
and
COS([Id] * PI() / 180)
In the DB, for instance with an INSERT / UPDATE trigger each time an Id
is inserted or updated.
CREATE TRIGGER dbo.tiuCustomer ON dbo.Customer
FOR INSERT, UPDATE
AS BEGIN
UPDATE dbo.Customer
SET
cos_id = COS(Inserted.Id * PI() / 180),
sin_id = SIN(Inserted.Id * PI() / 180)
FROM Inserted
WHERE
dbo.Customer.CustomerID = Inserted.CustomerID -- Use the PK to link your table
-- with Inserted.
END
Upvotes: 1
Reputation: 122002
DECLARE @lat INT = 500,
@lon INT = 700
DECLARE @lat_s FLOAT = SIN(@lat * PI() / 180),
@lat_c FLOAT = COS(@lat * PI() / 180)
SELECT DISTINCT @lat, @lon, *
FROM (
SELECT
id,
journeyid,
((ACOS(@lat_s * SIN([id] * PI() / 180) + @lat_c * COS([id] * PI() / 180) * COS((@lon - [JourneyId]) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) AS dist
FROM dbo.Customer
) t
WHERE dist <= 10000
ORDER BY dist
Upvotes: 1