PostgreSQL加入两个值

时间:2015-06-24 15:22:22

标签: postgresql between cross-join

我有以下表格,我正在尝试查找县代码以查找数十万个城市的列表。

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创建那些不可能(或实用)的迷你奇迹,所以我希望有一些东西我错过了。

1 个答案:

答案 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(或任何不等式)是一个非常糟糕的主意。