我有以下表格,我正在尝试查找县代码以查找数十万个城市的列表。
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
);
我的第一种方法是在联接中使用“between”:
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条记录。我猜这个语法是一个美化的交叉连接?
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和/或我可以用表格本身的结构做些什么。
我已经看到这个问题发布在其他DBMS平台上了,但是我已经能够在其他数据库中使用PostgreSQL创建那些不可能(或实用)的迷你奇迹,所以我希望有一些东西我错过了。
答案 0 :(得分: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
(或任何不等式)是一个非常糟糕的主意。