Проблема:

У меня есть 1 таблица из примерно 5000 строк под названием import_cities

У меня есть 1 таблица из примерно 800 000 строк под названием postal_codes , содержащая города почтовых индексов

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

Если они точно совпадают (да, точно. Остальные города проверяются вручную), мне нужно обновить столбец для import_city и введите город из import_cities и город из postal_codes (рядом) в третью таблицу под названием import_cities_equiv

Что я пробовал: Добавляем индексы в таблицы и делаем запрос ниже. Это займет вечность ... :(

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 ;

Любая помощь или предложение приветствуются. Спасибо.

2
Adrian P. 30 Янв 2016 в 01:30

2 ответа

Лучший ответ

Запрос, по которому вы хотите получить информацию:

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).

Если вы не можете использовать remove lower(), измените таблицу, чтобы добавить новые столбцы и поместить в них значения в нижнем регистре. Затем создайте индекс для новых столбцов и используйте их в объединении.

2
Gordon Linoff 29 Янв 2016 в 22:40

Спасибо всем за то, что указали мне правильное направление.

После ваших советов были внесены некоторые изменения:

  • добавлены индексы для таблицы import_cities в столбцах destinationCity и destinationProvince
  • добавлены индексы в таблицу почтовых индексов в столбцах города и провинции
  • Предложение 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

Забегая вперед, я теперь могу построить запрос INSERT на PHP и сделать один запрос INSERT, чтобы вставить все эквивалентные города в третью таблицу. Спасибо вам всем.

0
Adrian P. 1 Фев 2016 в 15:14