2009-07-17 29 views
6

Tôi có một bảng DB bao gồm 2,5 tỷ bản ghi. Có trùng lặp với giai điệu 11 triệu. Cách nào nhanh nhất để xóa 11 triệu bản ghi này?Làm cách nào để xóa nhanh hơn?

+0

Chỉ để cung cấp chế độ xem hiệu năng hệ thống, truy vấn để nhận số lượng hàng trùng lặp mất 1 giờ 40 phút. –

+0

Tôi nghĩ rằng OP đã xóa tài khoản của anh ấy. – Shimmy

+0

Xin cảm ơn các bạn! Tôi phải sao chép các bản ghi duy nhất vào một bảng, cắt ngắn bảng gốc và sao chép lại dữ liệu duy nhất. – Chattz

Trả lời

1

đầu tiên đưa một chỉ mục trên cột hoặc cột mà xác định và chứa các giá trị nhân bản,

Sau đó, assumimg bảng có một khóa chính (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) 

Chú ý: Cũng có thể sử dụng Tối đa (PK), tất cả những gì bạn đang làm là xác định một bản ghi duy nhất để không xóa khỏi từng bộ bản sao

EDIT: Để loại bỏ việc sử dụng rộng rãi nhật ký giao dịch và phân vùng UNDO, bạn có thể lưu trữ các giá trị dupes trong một bảng tạm thời, và sau đó xóa các dupes f hoặc mỗi cặp trong một giao dịch duy nhất ...

Giả sử chỉ có một cột (gọi nó là Cola, một số) xác định các giá trị nhân bản ...

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; 

Không thử nghiệm, vì vậy cú pháp có thể neeed massage ...

0

Nếu bạn chắc chắn rằng bạn không thay đổi tính toàn vẹn của dữ liệu (tính toàn vẹn tham chiếu), vô hiệu hóa các ràng buộc (chỉ mục, các ràng buộc khác), thực hiện xóa, sau đó bật các ràng buộc. Trước tiên, bạn phải thử trước, để xem liệu làm mới các chỉ mục khi bật ít tốn thời gian hơn việc xóa chúng với chúng có được bật hay không.

Một số tối ưu hóa truy vấn cũng có thể hữu ích, nhưng không biết thêm chi tiết, chúng tôi đang thảo luận về mặt lý thuyết.

+1

Không thả chỉ mục trên các cột bạn đang sử dụng để tìm các bản sao, lặp lại việc quét toàn bộ 2.500.000.000 hàng sẽ rất rất chậm. – Richard

+0

Nó sẽ không lặp lại các lần quét bảng, nó sẽ thực hiện các phép nối bán băm nếu không có chỉ mục. – 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 
     ) 

hoặc thậm chí có này:

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

Cả hai truy vấn sẽ sử dụng khá hiệu quả HASH SEMI JOIN, sau này sẽ nhanh hơn nếu không có chỉ mục trên dup_field.

Bạn có thể bị cám dỗ sao chép các hàng, nhưng lưu ý rằng nhiều thông tin hơn REDOUNDO sẽ được tạo khi sao chép 2G hàng hơn khi xóa 11M.

+1

hiệu suất của bản cập nhật như thế nào khi kích thước bảng là 2,5 tỷ? –

+0

Tôi có cảm giác rằng truy vấn này là con chó chậm, nhưng có thể đạt được những gì OP cần. Điều này có thể được viết lại như là một tham gia? –

+0

Sẽ có một sắp xếp trên 'dupfield' (nếu không có chỉ mục trên đó), có thể mất nhiều thời gian. Tham gia vào 'rowid' sẽ là' HASH SEMI JOIN', chỉ là vài phút trên '2G' đối với các hàng' 11M'. Xóa chính nó cũng sẽ mất hàng chục phút, chủ yếu để tạo 'REDO' và' UNDO'. – Quassnoi

20

Xóa một bản sao khỏi nhiều người là một doanh nghiệp phức tạp và với nhiều bản ghi đó, bạn gặp sự cố.

Một tùy chọn là bật vấn đề trên đầu của nó và sao chép các bản ghi bạn muốn lưu vào bảng mới. Bạn có thể sử dụng cú pháp CREATE TABLE AS SELECT DISTINCT ... NOLOGGING, cú pháp này sẽ sao chép các bản ghi đã sao chép của bạn mà không sử dụng nhật ký giao dịch, nhanh hơn nhiều. Khi bảng mới của bạn được điền, hãy xóa/đổi tên bảng cũ và đổi tên mới thành vị trí mới.

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

Oh, và nhớ để tát một chỉ số UNIQUE trên bảng mới để điều này không xảy ra nữa.

Đạo đức của câu chuyện là ... không bao giờ sử dụng DELETE để loại bỏ số lượng lớn các bản ghi, thật khủng khiếp vì nó phải lưu trữ tất cả các bản ghi đã xóa trong nhật ký làm lại. Hoặc là sao chép và chuyển đổi hoặc TRUNCATE.

+8

... và bạn có thể áp dụng cùng một thuật toán cho nhóm sản xuất sản phẩm chỉ cho phép 11.000.000 hàng trùng lặp ;-) Keith. – corlettk

+2

+1 cho câu trả lời này. Tôi chắc chắn sẽ bị cám dỗ để tạo ra một bản sao mới của bảng và chèn vào đó. Điều quan trọng tôi muốn thêm, không đặt bất kỳ chỉ mục nào trên bảng phụ đó cho đến khi bạn sao chép dữ liệu qua - bạn không muốn lần truy cập không cần thiết của nó phải giữ chỉ mục lên đến đầu trong khi chèn dữ liệu.Tôi cũng thích cách tiếp cận này vì nó có thêm một mạng lưới an toàn - bạn không phải loại bỏ bảng cũ cho đến khi chắc chắn 100% bạn đã có tất cả các dữ liệu chính xác. – AdaTheDev

+2

nó sẽ là thú vị để so sánh thời gian cần để sao chép 2,489 tỷ hồ sơ và xóa 11 triệu, sử dụng cùng một vị ngữ –

2

Việc xóa các hàng hiện có hay tạo bảng mới thích hợp và giảm bảng cũ nhanh hơn phụ thuộc vào nhiều yếu tố. 11 triệu hàng là rất nhiều, nhưng nó chỉ chiếm 0,5% tổng số hàng trong bảng. Hoàn toàn có thể là việc khôi phục mức giảm & có thể chậm hơn nhiều so với xóa, tùy thuộc vào số lượng chỉ mục tồn tại trên bảng nguồn, cũng như nơi các hàng cần xóa tồn tại trên các trang dữ liệu.

Sau đó, có vấn đề về việc liệu bảng nguồn có đang hoạt động hay không. Nếu có chèn & cập nhật đang diễn ra trong khi quá trình dọn dẹp này xảy ra, bản sao thả & sẽ không hoạt động nếu không có số lượng mã bổ sung hợp lý để đồng bộ hóa bảng sau khi thực tế.

Cuối cùng, tại sao cần phải thực hiện thao tác này "nhanh"? Có phải vì hệ thống cần phải ngoại tuyến trong khi quá trình diễn ra không? Bạn có thể viết một thủ tục loại bỏ các dupes trong khi hệ thống đang hoạt động, nhưng không ảnh hưởng đến phần còn lại của hệ thống về mặt tiêu thụ hoàn tác. Chúng tôi đã giải quyết được vấn đề này trong quá khứ bằng cách đầu tiên viết một truy vấn mà thu thập các từ khóa chính của các hàng phải được loại bỏ trong một bảng thứ hai, như vậy:

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

CREATE UNIQUE INDEX PK_RowsToDelete ON RowsToDeleteTable (PKColumn); 

Sau đó, chúng tôi có một/block PL SQL mà một trong hai vòng so với hàng trong một con trỏ như sau:

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; 

hoặc làm điều gì đó như thế này:

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; 

các vòng lặp và "SELECT MAX" rõ ràng là kém hiệu quả, nhưng nó có lợi thế là cho phép bạn t o thực hiện theo tiến trình của thao tác xóa. Chúng tôi đặt một chút mã chờ đợi trong vòng lặp để cho phép chúng tôi kiểm soát hoạt động gặt hái mạnh mẽ như thế nào.

Việc tạo RowsToDeleteTable ban đầu diễn ra rất nhanh và bạn có lợi thế cho phép quá trình thực hiện bao lâu tùy thích. Trong trường hợp như thế này, các "lỗ hổng" còn lại trong phần mở rộng của bạn bằng cách xóa sẽ không quá tệ, vì bạn đang xóa một tỷ lệ phần trăm nhỏ trong tổng số dữ liệu.

Các vấn đề liên quan