2015-08-31 5 views
0

У меня есть запрос SQL-обновления, который работает с моими тестовыми данными, но не заполняет (2 часа и более) мои данные о производстве.Обновление SQL с подзапросом занимает слишком много времени для запуска

Цель запроса

У меня есть таблица адресов, который использует кодовые строки вместо идентификаторов. Так, например, ADDRESSES.COUNTRY_CODE = «США» вместо 3152. Для ссылочной целостности я меняю эти строки кода на идентификаторы кода.

Схема

АДРЕСА (~ 356,000 записей)

  • ADDR_ID (ПК)
  • COUNTRY_CODE (VARCHAR)
  • Строка адреса 1 (VARCHAR)
  • т.д.

COUNTRY_CODES

  • CODE_ID (ПК)
  • CODE_STRING (VARCHAR)
  • т.д.

Шаги

Во-первых, создать временную таблицу для хранения адресов записей соответствующий код ID:

CREATE TABLE ADDRESS_TEMP 
AS 
    SELECT ADDR_ID, CODE_ID 
    FROM ADDRESSES 
      LEFT JOIN 
      COUNTRY_CODES 
      ON ADDRESSES.COUNTRY_CODE = CODE_STRING 

Во-вторых, я null столбец COUNTRY_CODE и измените его тип на NUMBER.

В-третьих, я установить столбец country_code к идентификаторам код:

UPDATE ADDRESSES 
    SET COUNTRY_CODE = 
      (SELECT ADDRESS_TEMP.CODE_ID 
      FROM ADDRESS_TEMP 
      WHERE ADDRESS_TEMP.ADDR_ID = ADDRESSES.ADDR_ID) 

Именно этот третий шаг, который принимает часов, чтобы завершить (2 часа) и подсчета голосов. Таблица ADDRESSES имеет ~ 356 000 записей. Ошибок нет; он все еще работает.

Вопрос

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

+0

Я бы подумал, что запрос на обновление будет влиять на каждую строку в вашей таблице, поскольку в ней нет предложения where. Вы пытались запустить SQL Profiler, чтобы узнать, что на самом деле передается в вашу базу данных? –

+0

Я понимаю, что вы имеете в виду, @SimonPrice, но этот запрос успешно завершается с ожидаемыми результатами с гораздо меньшим набором данных. Я не совсем уверен, как работает подзапрос update-set-subquery (я написал этот запрос несколько месяцев назад), поэтому я перейду к документации, чтобы обновить мою память. – DavidS

+1

Попробуйте добавить индекс в ADDRESS_TEMP В столбце ADDR_ID. – RBarryYoung

ответ

3

Догадка о внутренних компонентах Oracle Optimizer: «ADDRESS_TEMP» не имеет первичного ключа или индекса на addr_id. Поэтому обновление действительно использует подход n^2. Он в основном сканирует таблицу temp для каждой строки в таблице адресов.

Итак, рекомендация: сделайте addr_id Первичным ключом таблицы temp.

Если это не поможет нам получить дерево выполнения, которое создает оптимизатор Oracle. Это даст больше ясности в том, что на самом деле происходит за кулисами.

+0

После того, как ADDRESS_TEMP.ADDR_ID выполнил первичный ключ, для выполнения запроса потребовалось 3,5 минуты. Это мой первый реальный опыт работы с важностью индексов - это открытие. – DavidS

+0

@DavidS Я удивлен, что запрос не будет использовать хеш-соединение между адресами и address_temp, и задаться вопросом, не было ли статистики в таблице address_temp и что исказило план выполнения. Обновление, основанное на хеш-соединении, должно быть быстрее, чем одно, основанное на вложенных циклах, где все строки соединены. Вам нужно будет посмотреть план объяснения до и после, чтобы убедиться, но, пожалуйста, не узнайте из этого, что «indexes = good, full table scans = bad» - это грубое упрощение, особенно для массовых манипуляций с данными этого типа. –

+0

Большая часть этого проделала над моей головой, @DavidAldridge, потому что я знаю только базовый SQL, но я ценю, что вы предупреждаете меня о том, чтобы перескакивать на выводы. – DavidS

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