【问题标题】:Validate fields from one table to another in MySQL在 MySQL 中验证从一个表到另一个表的字段
【发布时间】:2016-01-29 22:30:41
【问题描述】:

问题:

我有一张名为 imported_cities

的大约 5000 行

我有一张名为 postal_codes 的大约 800 000 行 表,其中包含邮政编码城市

我需要根据城市名称及其省份根据邮政编码表中的城市验证imported_cities 中的每个不同城市。请参阅下面的表格结构。

如果它们完全匹配(是的,完全匹配。其余城市是手动验证的)我必须更新imported_city上的列和 将 city from imports_citiescity from postal_codes(并排)输入名为 imported_cities_equiv第三个表格 p>

我尝试过的: 向表中添加索引并在下面进行查询。 这需要永远...... :(

explain SELECT DISTINCT ic.destinationCity, pc.city FROM (imported_cities ic, postalcodes pc)
WHERE LOWER(ic.destinationCity) = LOWER(pc.city) 

结果

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE ip index NULL  company_city 478 NULL 4221 Using index; Using temporary 
1 SIMPLE pc index NULL city_prov 160 NULL 765407 Using where; Using index; Using join buffer (Block...

--

-- 表postalcodes的表结构

CREATE TABLE IF NOT EXISTS `postalcodes` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `code` varchar(11) NOT NULL,
  `city` varchar(50) NOT NULL,
  `province` varchar(50) NOT NULL,
  `provinceISO` varchar(2) NOT NULL,
  `latitude` decimal(17,13) NOT NULL,
  `longitude` decimal(17,13) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `code` (`code`),
  KEY `city_prov` (`city`,`provinceISO`)

--

-- 表imported_cities的表结构

CREATE TABLE IF NOT EXISTS `imported_cities` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `companyName` varchar(30) CHARACTER SET utf8 NOT NULL,
  `destinationCity` varchar(128) CHARACTER SET utf8 NOT NULL,
  `destinationProvince` varchar(20) CHARACTER SET utf8 NOT NULL,
  `equivCity` varchar(128) CHARACTER SET utf8 DEFAULT NULL,
  `minAmount` decimal(6,2) NOT NULL
  PRIMARY KEY (`id`),
  KEY `company_city` (`companyName`,`destinationCity`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci     AUTO_INCREMENT=7933 ;

--

-- 表imported_cities_equiv的表结构

CREATE TABLE IF NOT EXISTS `imported_cities_equiv` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `imported_city` varchar(128) CHARACTER SET utf8 NOT NULL,
  `pc_city` varchar(128) CHARACTER SET utf8 NOT NULL,
  `province` varchar(20) CHARACTER SET utf8 NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=149 ;

感谢任何帮助或建议。谢谢。

【问题讨论】:

  • 此外,您的查询将永远持续下去,因为它基本上是在 pc 上进行表扫描,您有大约 800K 行并且它正在查看 765407,除了乘以它正在查看的 ip在 4221 ...您必须添加正确的索引,加入 ON 子句以正确建立表之间的关系,和/或通过添加附加 where 子句参数来优化搜索...。

标签: mysql select left-join


【解决方案1】:

您要获取您的信息的查询是:

SELECT ip.*, (pc.city is not null) as exact match
FROM imported_prices ip left join
     postalcodes pc
     on LOWER(ip.destinationCity) = LOWER(pc.city)  and
        lower(ip.province) = lower(pc.province);

但是,这会产生非常糟糕的性能。摆脱 lower() 会有所帮助:

SELECT ip.*, (pc.city is not null) as exact match
FROM imported_prices ip left join
     postalcodes pc
     on(ip.destinationCity) =(pc.city)  and
       (ip.province) = (pc.province);

因为这样您就可以在postalcodes(city, province) 上添加索引。

如果您无法使用删除lower(),则更改表以添加新列并将小写值放入这些列中。然后在新列上建立索引并在连接中使用它们。

【讨论】:

  • “完全匹配”不适用于 MySQL。我试过这个: SELECT ip.destinationCity, (pc.city is not null) as city FROM import_prices ip left join postalcodes pc on BINARY ip.destinationCity = BINARY pc.city and (ip.destinationProvince) = (pc.province);但是查询花了 2 多分钟才返回 1000 行
【解决方案2】:

感谢大家为我指明正确的方向。

根据您的建议进行了一些更改:

  • 在destinationCity 和destinationProvince 列的imported_cities 表中添加了索引
  • 在城市和省 ISO 列的邮政编码表中添加了索引
  • JOIN 子句只有一侧大写,因为字段 ic.destinationCity 已经是大写了
  • 按省份限制查询 WHERE 以获得性能

最终的SQL是:

SELECT DISTINCT pc.city, pc.provinceISO
FROM  postalcodes pc
    LEFT JOIN imported_cities ic
     ON upper(pc.city) = ic.destinationCity AND
     pc.provinceISO = ic.destinationProvince
     WHERE ic.destinationProvince = 'QC';

然后解释

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  pc  ref province    province    8   const   278115  Using index condition; Using temporary
1   SIMPLE  ip  ref destinationCity,destinationProvince destinationCity 386 func    1   Using index condition; Using where; Distinct

接下来,我现在可以在 PHP 上构建 INSERT 查询并进行一个 INSERT 查询以在第三张表中插入所有等效城市。谢谢大家。

【讨论】:

  • 很好奇,该查询现在运行需要多长时间?这些表的大小会增长还是它们是静态行?
  • 邮政编码每年增长一次,但幅度不大。导入的城市每年最多可以增长 1000 个,但一般来说,它们是静态表格。查询需要 1-3 秒。足够好。
  • 这个查询多久运行一次? 1-3 秒可能看起来 good enough 现在但在规模上你需要减少几秒钟......
  • 同意,但是在导入新城市时查询每年运行 4 次。
猜你喜欢
  • 1970-01-01
  • 2012-06-25
  • 1970-01-01
  • 2010-11-13
  • 2017-08-09
  • 1970-01-01
  • 1970-01-01
  • 2020-02-17
  • 1970-01-01
相关资源
最近更新 更多