2015-03-16 6 views
1

Я написал sql для таблицы, которая имеет около 50.000.000 пользователей. Запрос занимает слишком много времени, чем я ожидал, что он не закончил около 23 часов.Как написать эффективный UPDATE-SELECT sql

UPDATE users 
    SET building_id = B.id 
    FROM (
     SELECT * 
     FROM buildings B 
    ) AS B 
    WHERE B.city   = address_city 
     AND B.town   = address_town 
     AND B.neighbourhood = address_neighbourhood 
     AND B.street  = address_street 
     AND B.no   = address_building_no 

Идея этого SQL заключается в том, что извлекать данные здания/адреса пользователей и вместо того, чтобы ссылаться на него в таблице зданий.

EXPLAIN

Update on users (cost=22226900.43..22548054.14 rows=15212 width=166) 
-> Merge Join (cost=22226900.43..22548054.14 rows=15212 width=166) 
     Merge Cond: (((users.address_city)::text = (b.city)::text) AND ((users.address_town)::text = (b.town)::text) AND ((users.address_neighbourhood)::text = (b.neighbourhood)::text) AND ((users.address_street)::text = (b.street)::text) AND ((users.address_building_no)::text = (b.no)::text)) 
     -> Sort (cost=21352886.76..21401078.96 rows=96384398 width=156) 
       Sort Key: users.address_city, users.address_town, users.address_neighbourhood, users.address_street, users.address_building_no 
       -> Seq Scan on users (cost=0.00..2559921.19 rows=96384398 width=156) 
     -> Materialize (cost=874013.68..883606.86 rows=9593179 width=63) 
       -> Sort (cost=874013.68..878810.27 rows=9593179 width=63) 
        Sort Key: b.city, b.town, b.neighbourhood, b.street, b.no 
        -> Seq Scan on buildings b (cost=0.00..136253.54 rows=9593179 width=63) (10 rows) 

Я не знаю, использует ли SQL внутренний SELECT, SQL для каждого из пользователей или кэши для сделки. Кроме того, если он кэширует, использует ли он индексы для кэшированной таблицы temp?

Я не мог писать SQL так:

FROM (
    SELECT * 
    FROM buildings B 
    WHERE B.city   = users.address_city 
    AND B.town   = users.address_town 
    AND B.neighbourhood = users.address_neighbourhood 
    AND B.street  = users.address_street 
    AND B.no   = users.address_building_no 
) 

он говорит, что users не могут быть доступны из внутреннего выбора. Есть ли у вас предложение получить доступ к зданиям во внутреннем заявлении sql.

+1

первый я не будет использовать select * вместо выбора полей, которые вы действительно используете. Я бы попробовал использовать Toad или другую программу, которая может помочь вам оптимизировать запросы. Также вы можете поговорить с вашим dba, чтобы проверить правильность индексов. – Veelicus

+1

Можете ли вы показать нам вывод 'EXPLAIN' для вашего первого запроса? –

+1

Вы проверили, есть ли активные блокировки таблиц или строк? И, пожалуйста, отпустите подзаголовок, вам это не нужно. –

ответ

1

Я полагаю

create table t as select column_list from a join b on column=column; 
alter table t rename to users; 

будет быстрее, и будет производить микросекунды запирать только ... Конечно, если таблица не редактируется в данный момент и есть достаточно места в temp_tablespace

0

Не уверен, но не будет ли это (хотя бы слегка, если не значительно) быстрее?

UPDATE users 
SET building_id = B.id 
FROM buildings B 
WHERE B.city   = address_city 
    AND B.town   = address_town 
    AND B.neighbourhood = address_neighbourhood 
    AND B.street  = address_street 
    AND B.no   = address_building_no 

Если ничего другого, он не будет требовать Materialize стадии, как указано в EXPLAIN выше.

+0

Я не знал, что мы можем просто «ОТ buildnigs B», пока не увидим его в комментариях. Тем не менее, это не меняет производительности, движок db оптимизирует их одинаково. –

+0

В этом случае возможно, что вы ищете неправильный конец для решения. В то время как на нем обе таблицы имеют соответствующие индексы в указанных 5 полях? Если нет, сканирование Seq неизбежно, и тогда любая форма повторной записи запроса не сделает это ОБНОВЛЕНИЕ более быстрым. –

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