I have a table (Location_Tree
) containing location information, arranged in a Id/ParentId structure on several levels, from level 0 of "World" right down to individual cities, via worldregions, countries, states, counties, cantons and cities. We have another table of incidents which has a column "CreatedWithLocationId" which indicates the location for the incident, but there is nothing to say whether the location provided is a city, county, country or whatever - in other words the accuracy is undefined.
I am using a query to make a report that takes the location of one incident and shows other incidents that are listed "nearby". the best matches will be those that share a location with the input location, but if not enough matches are found, I am "zooming out" of the location, to search the parent locations up the tree until I find enough matches for the report requirements.
In order to achieve this, I have made a recursive CTE, which will get all the children of a given location from the Location_Tree table. So I take my input location, find the parentId and then find all the locations that share that parentId, or have it as grandparents and so on, limiting by level and so on as required.
DECLARE @Ancestor_Id INT = 1;
WITH Location_Children AS
(
SELECT @Ancestor_Id AS Id, NULL AS ParentId
UNION ALL
SELECT
B.Id, B.ParentId
FROM Location_Tree AS B
INNER JOIN Location_Children AS C ON B.ParentId = C.Id
)
SELECT * FROM Location_Children;
Even if the only row that is returned is the @Ancestor_Id AS Id, NULL AS ParentId
row, the above query always causes a clustered index scan on the primary key of the Location_Tree
table () and an eager spool - All the vast number of rows are involved in the execution plan and the query takes about 15 seconds to complete, returning my one row.
Does anyone have any suggestions about how I might go about speeding things up a bit? I have tried adding indexes and so on, and I'm a bit reluctant to do a massive query to use CASE
statements or a series of left joins to replace the CTE, as it will take a lot of scripting... I have tried every permutation of this query, using inline functions, custom table data types, (almost) everything and to no avail... What should I try next?