2009-02-12 68 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