2009-07-17 3 views
6

У меня есть таблица DB, которая состоит из 2,5 миллиардов записей. Есть дубликаты на сумму 11 миллионов. Какой самый быстрый способ удалить эти 11 миллионов записей?Как удалить быстрее?

+0

Чтобы получить представление о производительности системы, запрос на получение подсчета повторяющихся строк занял 1 час и 40 минут. – 2009-07-17 13:24:23

+0

Я думаю, что OP удалил свою учетную запись. – Shimmy

+0

Спасибо, ребята! Мне пришлось копировать уникальные записи в таблицу, обрезать исходную таблицу и копировать уникальные данные. – Chattz

ответ

1

Сначала положить индекс столбца или столбцов, которые определяют и содержат повторяющиеся значения,

Затем assumimg таблицу имеет первичный ключ (PK),

Delete Table T Where PK <> 
     (Select Min(PK) From Table 
     Where ColA = T.ColA 
      ... for each column in set defined above 
      And ColB = T.ColB) 

ПРИМЕЧАНИЕ: Можно также использовать Max (PK), все, что вы делаете, это идентификация одной записи, которая не удаляется из каждого набора дубликатов.

EDIT: Чтобы исключить широкое использование журнала транзакций и раздела UNDO, вы можете сохранить значения, которые обманы в таблице temp, а затем удалить обманы f или каждая пара внутри одной транзакции ...

Предполагая, что только один столбец (назовем его COLA, число) определяет простофили ...

Create Table Dupes (ColA Number) 
    Insert Dupes(ColA) 
    Select Distinct ColA 
    From Table 
    Group By ColA 
    Having Count(*) > 1 

    recordExists Number := 0 ; 
    ColAValue Number; 
    Select Case When Exists (Select Count(*) From Dupes) 
    Then 1 Else 0 End Into recordExists From Dual; 


    While recordExists = 1 
     Loop 
     Select (Select Max(ColA) From Dupes) 
     Into ColAValue From Dual; 
     Begin Transaction 
      Delete Table T 
      Where ColA = ColAValue 
       And pk <> (Select Min(Pk) From Table 
          Where ColA = ColAValue); 
      Delete Dupes Where ColA = ColAValue; 
     Commit Transaction; 
     Select Case When Exists (Select Count(*) From Dupes) 
     Then 1 Else 0 End Into recordExists From Dual; 
     End Loop; 

Не протестировано, так что синтаксис может массировать ... нужду

0

Если вы уверены, что не изменяете целостность данных (ссылочная целостность), отключите ограничения (индексы, другие ограничения), выполните удаление, а затем включите ограничения. Сначала вы должны попробовать, чтобы убедиться, что обновление индексов при включении занимает меньше времени, чем удаление с ними.

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

+1

Не отбрасывайте указатель в столбцах, которые вы используете, чтобы найти дубликаты, повторное полное сканирование таблицы в 2500 000 000 строк будет очень очень медленным. – Richard

+0

Он не будет выполнять повторное сканирование таблицы, он будет делать хэш-полуфиналы, если нет индексов. – Quassnoi

3
DELETE 
FROM mytable 
WHERE rowid IN 
     (
     SELECT rowid 
     FROM (
       SELECT rowid, ROW_NUMBER() OVER (ORDER BY dupfield) rn 
       FROM mytable r 
       ) 
     WHERE rn > 1 
     ) 

или, может быть, даже это:

DELETE 
FROM mytable mo 
WHERE EXISTS 
     (
     SELECT NULL 
     FROM mytable mi 
     WHERE mi.dup_field = mo.dup_field 
       AND mi.rowid <> mo.rowid 
     ) 

Оба эти запросы будут использовать весьма эффективно HASH SEMI JOIN, последний будет быстрее, если нет индекса на dup_field.

Вы можете захотеть скопировать строки, но учтите, что гораздо больше REDO и UNDO информации будет генерироваться при копировании 2G строк, чем при удалении 11M.

+1

Как работает обновление такого размера, когда размер таблицы составляет 2,5 миллиарда? –

+0

У меня такое ощущение, что этот запрос медленный, но он может достичь того, что требуется OP. Может ли это быть переписано как соединение? –

+0

Будет сортировка по 'dupfield' (если на нем нет индекса), что может занять много времени. Присоединение к 'rowid' будет' HASH SEMI JOIN', что является вопросом минут на '2G' против' 11M' строк. Само удаление также займет десятки минут, в основном для генерации 'REDO' и' UNDO'. – Quassnoi

20

Удаление одного дубликата из многих - это сложный бизнес, и с этим множеством записей у вас есть проблема.

Один из вариантов заключается в том, чтобы повернуть проблему на голову и скопировать записи, которые вы хотите сохранить в новую таблицу. Вы можете использовать синтаксис CREATE TABLE AS SELECT DISTINCT ... NOLOGGING, который скопирует ваши дедуплицированные записи, не используя журнал транзакций, что намного быстрее. После заполнения новой таблицы удалите/переименуйте старый и переименуйте новый.

См http://www.databasejournal.com/features/oracle/article.php/3631361/Managing-Tables-Logging-versus-Nologging.htm

О, и помните, хлопнуть уникальный индекс для новой таблицы, так это не повторилось.

Мораль истории ... never использовать DELETE для избавления от большого количества записей, это ужасно медленно, потому что оно должно хранить все удаленные записи в журнале повтора. Либо копировать и переключаться, либо TRUNCATE.

+8

... и вы можете применить тот же алгоритм к команде, которая произвела продукт, который позволил только 11 000 000 повторяющихся строк ;-) Keith. – corlettk

+2

+1 за этот ответ. У меня наверняка возникнет соблазн создать новую копию таблицы и вставить ее в нее. Ключевая вещь, которую я бы добавил, - это не помещать какие-либо индексы на эту вторичную таблицу, пока вы не скопируете эти данные - вы не хотите, чтобы ненужный урон был вынужден держать индексы до нуля при вставке данных.Мне также нравится этот подход, поскольку у него есть дополнительная защитная сетка - вам не нужно избавляться от старой таблицы, пока вы не убедитесь, что у вас есть все нужные данные. – AdaTheDev

+2

было бы интересно сравнить время, которое требуется, чтобы скопировать 2,489 миллиарда записей против удаления 11 миллионов, используя те же предикаты –

2

Следует ли удалять существующие строки или создавать надлежащую новую таблицу, а старые - быстрее, зависит от множества факторов. 11 миллионов строк - это много, но это всего лишь 0,5% от общего количества строк в таблице. Вполне возможно, что воссоздание & может быть намного медленнее, чем удаление, в зависимости от того, сколько индексов существует в исходной таблице, а также где строки, которые необходимо удалить, существуют на страницах данных.

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

И, наконец, почему необходимо, чтобы эта операция была «быстрой»? Это потому, что система должна быть отключена во время процесса? Вы можете написать процедуру, которая удаляет обманки, пока система работает вживую, но не влияет на остальную часть системы с точки зрения уничтожения. Мы решили эту проблему, в прошлом первого написания запроса, который собирает первичные ключи строк, которые будут удалены во второй таблице, например, так:

INSERT 
    INTO RowsToDeleteTable 
    SELECT PKColumn 
    FROM SourceTable 
    WHERE <conditions used to find rows to remove> 

CREATE UNIQUE INDEX PK_RowsToDelete ON RowsToDeleteTable (PKColumn); 

Тогда мы имеем/SQL блока PL что либо петли по рядам в курсоре, как так:

BEGIN 
    FOR theRow IN (SELECT PKColumn FROM RowsToDeleteTable ORDER BY 1) LOOP 
    <delete source table for theRow.PKColumn) 
    <optionally wait a bit> 
    commit; 
    END LOOP; 
END; 

или делает что-то вроде этого:

BEGIN 
    FOR theRow IN (SELECT MIN(PKColumn) FROM RowsToDeleteTable) LOOP 
    <delete source table for theRow.PKColumn) 
    <optionally wait a bit> 
    DELETE RowsToDeleteTable 
    WHERE PKColumn = theRow.PKColumn; 
    commit; 
    END LOOP; 
END; 

зацикливание и «SELECT MAX», очевидно, менее эффективен, но имеет то преимущество, что позволяет вам т o следить за ходом операции удаления. Мы поставили немного кода ожидания в цикле, чтобы мы могли контролировать, как сильно происходит операция по извлечению.

Начальное создание RowsToDeleteTable происходит очень быстро, и у вас есть преимущество, позволяющее процессу принимать столько, сколько захотите. В таком случае «дыры», оставшиеся в экстентах с помощью удалений, будут не слишком плохими, так как вы удаляете такой небольшой процент от общего количества данных.

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