2015-09-20 3 views
1

Я пытаюсь перенести некоторые данные в новую структуру, но это заставляет меня навсегда.Запрос чрезвычайно медленный из-за подзапросов

Запрос заключается в следующем:

INSERT INTO atemp_addresses (id, city, state, country_id) 
SELECT id, (SELECT name from cities WHERE id=adr.city_id limit 1), 
(SELECT name FROM states WHERE id=(SELECT state_id FROM cities WHERE id=adr.city_id limit 1) limit 1), (SELECT country_id FROM states WHERE id=(SELECT state_id FROM cities WHERE id=adr.city_id limit 1) limit 1), FROM addresses adr 

Поскольку данные хранятся в других таблицах, я должен использовать все эти подзапросы, что замедляет ее много. Есть ли более быстрый способ сделать это?

+0

«Поскольку данные хранятся в других таблицах, я должен использовать все эти подзапросы« ... вы должны объединять таблицы вместе в предложении FROM. –

+0

Я знаю, что могу показаться грубым, но, ты не возражаешь помочь мне в этом? Раньше я никогда не использовал союзы, никогда не понимал, как они работают. –

ответ

2

Это ваш запрос:

INSERT INTO atemp_addresses (id, city, state, country_id) 
    SELECT id, 
      (SELECT name from cities WHERE id = adr.city_id limit 1), 
      (SELECT name FROM states WHERE id = (SELECT state_id FROM cities WHERE id=adr.city_id limit 1) limit 1), 
      (SELECT country_id FROM states WHERE id=(SELECT state_id FROM cities WHERE id=adr.city_id limit 1) limit 1) 
    FROM addresses adr; 

Многократно, вы используете LIMIT без ORDER BY. Это означает, что вы получите произвольную совпадающую строку, которая может меняться от одного вызова к другому.

Эквивалентный запрос должен быть:

INSERT INTO atemp_addresses (id, city, state, country_id) 
    SELECT adr.id, c.name, s.name, s.country_id 
    FROM addresses adr JOIN 
     cities c 
     ON adr.city_id = c.id JOIN 
     states s 
     ON c.state_id = s.id; 

Использование LIMIT предполагает, что там может быть больше, чем один город с тем же id (признак плохого дизайна базы данных?). Если да, то:

INSERT INTO atemp_addresses (id, city, state, country_id) 
    SELECT DISTINCT ON (adr.id) adr.id, c.name, s.name, s.country_id 
    FROM addresses adr JOIN 
     cities c 
     ON adr.city_id = c.id JOIN 
     states s 
     ON c.state_id = s.id 
    ORDER BY adr.id; 
+0

Я забыл упомянуть, извините за это. Я использовал ограничения производительности, я видел, что если я ограничу его до 1, он будет быстрее, вероятно, потому, что он прекратит поиск, как только он найдет запись. –

+0

Если столбец 'id' является первичным ключом - оптимизатор запросов postgresql должен быть достаточно умным, чтобы вывести его сам. – zerkms

+0

Итак, ваш запрос выполнил задание, через 31 секунду (мой запрос не закончился в часах). Одна из проблем, которую я вижу сейчас, состоит в том, что она не перемещала все записи. В некоторых адресах может быть city_id = 0, что означает, что у них нет соответствующей записи в таблице городов. Соединение просто заставило бы пропустить запись адреса, поскольку она не находит совпадения в других, я прав? Если да, есть ли способ, которым я могу их переместить, даже если city_id нет в городах? Кроме того, на данный момент, я хочу поблагодарить вас. Вы помогли мне добиться огромного прогресса, и ваш пример просто заставил меня понять, как работает JOIN. –

Смежные вопросы