2015-06-24 65 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分鐘的時間。郵政編碼表有大約80,000條記錄。我猜這個語法是一個榮耀的交叉連接?

無論是從和通碼索引,並且我已經在結構控制,這樣我就可以改變表,如果有幫助。

我唯一的想法等是繼續前進,擴大表到所有可能的值 - 類似於此:

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

這將擴大數據超過20萬條記錄,這是不是一個大問題,但我不確定這是否是我唯一的追求不是可怕的疑問。

我猜測,即使這樣做在飛行中,沒有索引將優於between在我的連接,但我希望有一個替代方案,無論是在我的SQL和/或我可以做與表本身的結構。

我已經看到這個問題已發佈給其他DBMS平臺,但我已經能夠用PostgreSQL實現在其他數據庫中不可能(或實用)的迷你奇蹟,所以我希望有一些東西我錯過了。

+0

你對'城市(ZIP_CODE)'和'縣(zip_code_from,zip_code_thru')的指數? –

+0

作爲一個知道一些郵政編碼的人,我想說你們的「通過」方式對於縣來說是有缺陷的。沒有可以分配給縣的郵政編碼範圍。一些郵政編碼實際上跨越了多個縣。另外,有些城市有幾十個郵政編碼。假設您使用美國郵政編碼和美國縣。 – CoryatJohn

+0

@a_horse_with_no_name zip_code_from,zip_code_thru(單個索引,不是兩個單獨的索引)上有索引,cities.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是一個非常糟糕的主意。