2009-02-12 56 views
1

我有一个查询需要很长时间并且经常超时。这是一个基于接近的邮政编码搜索表值功能。无论如何索引基于查询,所以它不必每次重新计算所有这些值?邮政编码和邮政编码列表合计超过一百万行。对查询进行索引

这里是表格功能。

Create FUNCTION [dbo].[ZipsInRadius] (@zipCode varchar(15), 
    @radius int, @unit char(1)) 
RETURNS @areaResults TABLE(
    Zip varchar (30), 
    City varchar (255), 
    St varchar (20), 
    Lat decimal (16,12), 
    Long decimal (16,12))  
BEGIN 

    DECLARE @iStartLat decimal(16, 12) 
    DECLARE @iStartLong decimal(16, 12) 
    SELECT 
     @iStartLat = CAST(Latitude AS decimal(16, 12)), 
     @iStartLong = CAST(Longitude AS decimal(16, 12)) 
    FROM zip 
    WHERE zipcode LIKE @zipCode + '%' 
    SELECT 
     @iStartLat = CAST(Latitude AS decimal(16, 12)), 
     @iStartLong = CAST(Longitude AS decimal(16, 12)) 
    FROM postalcode 
    WHERE postalcode LIKE @zipCode + '%' 
    DECLARE @latRange decimal(16, 12) 
    DECLARE @longRange decimal(16, 12) 

    IF (@unit = 'K')   --Get distance in kilometers 
     BEGIN 
      SELECT @LatRange = 
       (CAST(@radius/((6076.0/5280.0) * 60.0) 
       AS decimal(16, 12))) * 0.621371 
      SELECT @LongRange = 
       (@radius/(((cos(@iStartLat * pi()/180.0) * 6076.0) 
       /5280.0) * 60)) * 0.621371 
     END 
    ELSE      --Get distance in miles (the default) 
     BEGIN 
      SELECT @LatRange = CAST(@radius/((6076.0/5280.0) * 60.0) 
       AS decimal(16, 12)) 
      SELECT @LongRange = 
       @radius/(((cos(@iStartLat * pi()/180.0) * 6076.0) 
       /5280.0) * 60) 
     END 

    DECLARE @lowLatitude decimal(16, 12) 
    DECLARE @highLatitude decimal(16, 12) 
    DECLARE @lowLongitude decimal (16, 12) 
    DECLARE @highLongitude decimal (16, 12) 
    SELECT @lowLatitude = @iStartLat - @latRange 
    SELECT @highLatitude = @iStartLat + @latRange 
    SELECT @lowLongitude = @iStartLong - @longRange 
    SELECT @highLongitude = @iStartLong + @longRange 

    INSERT INTO @areaResults (zip, city, st, lat, long) 
     SELECT ZIPcode, CITY, STate, LATitude, LONGitude 
     FROM Zip Z 
     WHERE Z.Latitude <= @highLatitude 
        AND Z.Latitude >= @lowLatitude 
      AND Z.Longitude >= @lowLongitude 
        AND Z.Longitude <= @highLongitude  
     INSERT INTO @areaResults (zip, city, st, lat, long) 
     SELECT postalcode, CITY, province, LATitude, LONGitude 
     FROM postalcode z 
     WHERE Z.Latitude <= @highLatitude 
        AND Z.Latitude >= @lowLatitude 
      AND Z.Longitude >= @lowLongitude 
        AND Z.Longitude <= @highLongitude 
    RETURN 
END 

回答

2

我会建议在经度和纬度上使用多列索引。

这很好,你正在使用一个边界框,这通常会加快你的查询。我提到的索引,你应该看到巨大的改进。

在附注中,您将纬度/经度存储在十进制(16,12)中。 12位数字的精度可能比你需要的吨数多。第五位数(以纬度/长度单位表示)约为3英尺。所以......第12位数字实际上可能代表纳米(或更少)。通过使用较小的数据类型,您的表(和索引)将更有效率。对于邮政编码搜索尤其如此,因为您拥有的经纬线是代表邮政编码中心的点,该位置并不是非常准确。对于经度,我通常使用十进制(8,5)。由于纬度通常在-90至90范围内,因此您可以用十进制(7,5)获得纬度。

+0

谢谢...我添加的指标,但我仍然问题。在问题的zip实际上返回98000行(它在多伦多),并需要41秒运行... – Shawn 2009-02-12 15:40:07

1

您可以尝试强行对你的索引INDEX JOIN,并看看是否有帮助:

CREATE INDEX ix_zip_lat ON zip(lat) 

CREATE INDEX ix_zip_long ON zip(long) 

SELECT * FROM zip 
WITH (INDEX(ix_zip_lat), INDEX (ix_zip_long)) 
WHERE lat BETWEEN @lowlat and @hilat 
     AND long BETWEEN @lowlong and @hilong