Индексирование по запросу - PullRequest
       16

Индексирование по запросу

1 голос
/ 12 февраля 2009

У меня есть запрос, который занимает слишком много времени и часто истекает. Это функция поиска по таблице значений по почтовому индексу на основе близости. Есть ли способ индексировать на основе запроса, чтобы не приходилось каждый раз пересчитывать все эти значения? Объединенный список почтовых индексов и почтовых индексов содержит более миллиона строк.

Вот табличная функция.

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

Ответы [ 3 ]

3 голосов
/ 12 февраля 2009

Это займет у меня миллисекунды, может быть, ваш подход неправильный, посмотрите здесь: Поиск по почтовому индексу SQL Server по широте / долготе 2000/2005 версия

или для версии 2008 с использованием типа данных geography здесь: Поиск близости SQL Server 2008 с типом данных Geography

2 голосов
/ 12 февраля 2009

Я бы порекомендовал многостолбцовый индекс по долготе и широте.

Хорошо, что вы используете ограничивающий прямоугольник, который обычно ускоряет ваш запрос. С указанным выше индексом вы должны увидеть огромные улучшения.

На боковой ноте ваши широта / долгота хранятся в десятичном виде (16,12). Точность на 12 цифр, вероятно, на тонны больше, чем вам нужно. Пятая цифра (в лат / длинные единицы) представляет приблизительно 3 фута. итак ... 12-ая цифра может фактически представлять нанометры (или меньше). Используя меньший тип данных, ваши таблицы (и индексы) будут более эффективными. Это особенно верно для поиска по почтовому индексу, потому что у вас есть широта / долгота, которые представляют собой центр почтового индекса, позиция не очень точная для начала. Для долготы я обычно использую десятичную (8,5). Поскольку широта обычно находится в диапазоне от -90 до 90, вы можете выбрать десятичную (7,5) для широты.

1 голос
/ 12 февраля 2009

Вы можете попытаться ввести 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...