2015-06-24 5 views
1

У меня есть следующие таблицы и я пытаюсь найти коды графства для списка из нескольких сотен тысяч городов.PostgreSQL Соединение между двумя значениями

create table counties (
    zip_code_from char(5) not null, 
    zip_code_thru char(5) not null, 
    county_code char(3) not null 
); 

create table cities (
    city  text not null, 
    zip_code char(5) not null 
); 

Мой первый подход с использованием «между» в соединении:

select 
    ci.city, ci.zip_code, co.county_code 
from 
    cities ci 
    join counties co on 
    co.zip_code between ci.zip_code_from and ci.zip_code_thru 

Я знаю, что в мире Oracle, это неодобрительно, и в самом деле производительность, кажется, быть несчастным. Для обработки около 16 000 городов требуется более 8 минут. Таблица zip-кода имеет около 80 000 записей. Я предполагаю, что этот синтаксис - это прославленное кросс-соединение?

Оба кода from и thru индексируются, и у меня есть контроль над структурами, поэтому я могу изменить таблицу, если это поможет.

Моя единственная другая мысль, чтобы идти вперед и расширить таблицу из всех возможных значений - что-то похожее на это:

select 
    generate_series (
    cast (zip_code_from as int), 
    cast (zip_code_thru as int) 
) as zip_code, 
    * 
from counties 

Это расширит данные более чем 200 000 записей, которая не является большое дело, но я не был уверен, что это мое единственное обращение к запросам, которые не ужасны.

Я предполагаю, что даже делать это на лету и не иметь индексов было бы предпочтительнее between в моем соединении, но я надеялся, что есть альтернатива, будь то с точки зрения моего SQL и/или что-то, что я могу со структурой самой таблицы.

Я видел этот вопрос, размещенный для других платформ СУБД, но я смог снять мини-чудеса с PostgreSQL, которые были невозможны (или практичны) в других базах данных, поэтому я был надежен, что есть что-то Я пропустил.

+0

У вас есть указатель на 'города (zip_code)' и 'counties (zip_code_from, zip_code_thru')? –

+0

Как кто-то, кто знает немного о Zip-кодексах, я бы сказал, что ваш подход «из-за» для округов испорчен. Нет никакого диапазона Zip-кодов, которые вы можете присвоить графству. Некоторые Zip-коды фактически пересекаются в несколько округов. Кроме того, в некоторых городах есть десятки Zip-кодов. Предполагается, что вы используете US Zip Codes и US Counties. – CoryatJohn

+0

@a_horse_with_no_name есть индекс на zip_code_from, zip_code_thru (один индекс, а не два отдельно) и ни один из городов.zip_code. Запрос просматривает всю таблицу городов, поэтому я не думал, что это поможет. Не так ли? – Hambone

ответ

0

Спустя несколько месяцев это снова обрезало голову, и я решил проверить некоторые из моих теорий.

Исходный запрос:

select 
    ci.city, ci.zip_code, co.fips_code 
from 
    cities ci 
    join counties co on 
    ci.zip_code between co.from_zip_code and co.thru_zip_code 

ли на самом деле реализовать декартовой. Запрос возвращает 34 000 строк и занимает 597 секунд.

Если я «предварительно взрываются» почтовый индекс колеблется в дискретные записи:

with exploded_zip as (
    select 
    generate_series (
     cast (from_zip_code as int), 
     cast (thru_zip_code as int) 
    )::text as zip_code, 
    * 
    from counties 
) 
select 
    ci.city, ci.zip_code, co.fips_code 
from 
    cities ci 
    join exploded_zip co on 
    ci.zip_code = co.zip_code 

Запрос возвращает те же строки, но заканчивается в 2,8 секунды.

Так что, судя по всему, использование between в соединении (или любое неравенство) - это действительно плохая идея.

Смежные вопросы