6

Chúng tôi có truy vấn để xóa một số hàng khỏi bảng dựa trên trường id (khóa chính). Đây là một truy vấn khá đơn giản:Cải thiện hiệu suất của Sql Xóa

delete all from OUR_TABLE where ID in (123, 345, ...) 

Vấn đề là không có. Id có thể rất lớn (ví dụ: 70k), do đó truy vấn mất nhiều thời gian. Có cách nào để tối ưu hóa điều này không? (Chúng tôi đang sử dụng Sybase - nếu điều đó quan trọng).

+0

là ASE này hoặc ASA? Bạn có biết số phiên bản của mình không? – AdamH

+0

Đây là phiên bản ASE 10x. – amit

Trả lời

3

Cân nhắc chạy theo lô. Một vòng lặp chạy 1000 bản ghi tại một thời điểm có thể nhanh hơn nhiều so với một truy vấn thực hiện mọi thứ và ngoài ra sẽ không giữ cho bảng bị khóa cho người dùng khác trong thời gian dài.

Nếu bạn có xóa tầng (và nhiều bảng khóa ngoài bị ảnh hưởng) hoặc trình kích hoạt có liên quan, bạn có thể cần chạy trong các lô nhỏ hơn. Bạn sẽ phải thử nghiệm để xem đó là con số tốt nhất cho tình huống của bạn. Tôi đã có bảng mà tôi đã phải xóa trong lô 100 và những người khác, nơi 50000 làm việc (may mắn trong trường hợp đó như tôi đã xóa một triệu hồ sơ).

Nhưng ngay cả tôi cũng sẽ đặt các giá trị chính mà tôi định xóa vào bảng tạm thời và xóa từ đó.

+1

+1 để đặt ID trong bảng tạm thời (hoặc bảng công việc vĩnh viễn cũng có thể hoạt động) –

3

Tôi tự hỏi nếu phân tích cú pháp một mệnh đề IN có 70K mục trong đó là một vấn đề. Bạn đã thử một bảng tạm thời với một tham gia thay thế?

+0

Không biết Sybase nhưng trong SQLServer này cũng sẽ là lần thử đầu tiên của tôi trong việc tối ưu hóa việc xóa. –

0

Liệu your_table có tham chiếu về xóa tầng không?

4

Có hai cách để lập báo cáo như thế này thực hiện:

  1. Tạo một bảng mới và sao chép tất cả ngoại trừ các hàng để xóa. Trao đổi các bảng sau đó (alter table name ...) Tôi khuyên bạn nên thử ngay cả khi nó có vẻ ngu ngốc. Một số cơ sở dữ liệu sao chép nhanh hơn nhiều so với lúc xóa.

  2. Phân vùng bảng của bạn. Tạo các bảng N và sử dụng một khung nhìn để kết hợp chúng thành một bảng. Sắp xếp các hàng thành các bảng khác nhau được nhóm theo tiêu chí xóa. Ý tưởng là để thả toàn bộ bảng thay vì xóa các hàng riêng lẻ.

+0

+1 đây sẽ là gợi ý của tôi. – Elijah

2

Sybase có thể xử lý các đối số 70K trong mệnh đề IN không? Tất cả các cơ sở dữ liệu tôi đã làm việc có một số giới hạn về số đối số cho mệnh đề IN. Ví dụ: Oracle có giới hạn khoảng 1000.

Bạn có thể tạo tùy chọn thay vì mệnh đề IN không? Điều đó sẽ rút ngắn sql. Có lẽ điều đó có thể giúp cho một số lượng lớn các giá trị trong mệnh đề IN. Một cái gì đó như thế này:

DELETE FROM OUR_TABLE WHERE ID IN 
     (SELECT ID FROM somewhere WHERE some_condition) 

Xóa số lượng lớn các hồ sơ có thể được tăng tốc với một số biện pháp can thiệp trong cơ sở dữ liệu, nếu giấy phép mô hình cơ sở dữ liệu. Dưới đây là một số chiến lược:

  1. bạn có thể tăng tốc độ bằng cách xóa chỉ mục, xóa bản ghi và tạo lại chỉ mục. Điều này sẽ loại bỏ các cây chỉ mục tái cân bằng trong khi xóa các bản ghi.

    • thả tất cả các chỉ số trên bàn
    • xóa các bản ghi
    • chỉ số tái
    • nếu bạn có rất nhiều mối quan hệ để bảng này, hãy thử tắt chế nếu bạn biết chắc chắn rằng lệnh xóa sẽ không phá vỡ bất kỳ vẹn hạn chế. Xóa sẽ đi nhanh hơn nhiều vì cơ sở dữ liệu sẽ không kiểm tra tính toàn vẹn. Bật các ràng buộc sau khi xóa.
    • disable ràng buộc toàn vẹn, vô hiệu hóa ràng buộc kiểm tra
    • xóa các bản ghi
    • cho phép hạn chế
    • disable trigger trên bàn, nếu bạn có bất kỳ và nếu quy tắc kinh doanh của bạn cho phép điều đó. Xóa bản ghi, sau đó bật trình kích hoạt.

    • cuối cùng, thực hiện theo đề xuất khác - tạo bản sao của bảng có chứa các hàng không bị xóa, sau đó thả bản gốc, đổi tên bản sao và tạo lại ràng buộc toàn vẹn, nếu có.

tôi sẽ cố gắng kết hợp của 1, 2 và 3. Nếu điều đó không làm việc, sau đó 4. Nếu mọi thứ đều chậm, tôi sẽ tìm kiếm hộp lớn - bộ nhớ hơn, đĩa nhanh hơn.

+0

Tắt trình kích hoạt là một ý tưởng rất tồi trừ khi bạn có thể ngăn người dùng khác thực hiện những việc trên cơ sở dữ liệu trong khi chúng bị tắt. – HLGEM

+0

Tôi biết, đó là lý do tôi viết "nếu quy tắc kinh doanh của bạn cho phép". Ví dụ, tôi đã thấy rất nhiều cơ sở dữ liệu trong đó trình kích hoạt được sử dụng cho một số loại thay đổi kiểm toán. Nếu anh ta cần hiệu suất, hơn loại kích hoạt này có lẽ có thể được loại bỏ. – zendar

2

Tìm hiểu điều gì đang sử dụng hết hiệu suất!

Trong nhiều trường hợp, bạn có thể sử dụng một trong các giải pháp được cung cấp. Nhưng có thể có những người khác (dựa trên kiến ​​thức của Oracle, vì vậy mọi thứ sẽ khác nhau trên cơ sở dữ liệu khác. Chỉnh sửa: chỉ thấy rằng bạn đã đề cập đến Sybase):

  • Bạn có chìa khóa nước ngoài trên bàn không? Đảm bảo rằng các id giới thiệu được lập chỉ mục
  • Bạn có các chỉ mục trên bảng đó không? Nó có thể là thả trước khi xóa và tái tạo sau khi xóa có thể nhanh hơn.
  • kiểm tra gói thực hiện. Có phải nó đang sử dụng một chỉ mục khi quét toàn bộ bảng có thể nhanh hơn không? Hoặc đường vòng khác? HINTS có thể giúp
  • thay vì chọn thành new_table như được đề xuất ở trên bảng tạo khi chọn có thể còn nhanh hơn.

Nhưng hãy nhớ: Tìm hiểu điều gì đang sử dụng hết hiệu suất trước tiên.

Khi bạn đang sử dụng câu lệnh DDL, hãy đảm bảo bạn hiểu và chấp nhận hậu quả có thể xảy ra đối với giao dịch và sao lưu.

1

Hãy thử sắp xếp ID bạn đang chuyển sang "trong" theo thứ tự như bảng hoặc chỉ mục được lưu trữ. Sau đó, bạn có thể nhận được nhiều lần truy cập hơn trên bộ nhớ cache trên đĩa.

Đưa ID bị xóa vào bảng tạm thời có các Id được sắp xếp theo thứ tự như bảng chính, có thể cho phép cơ sở dữ liệu quét đơn giản trên bảng chính.

Bạn có thể thử sử dụng nhiều hơn một kết nối và kích hoạt công việc qua các kết nối để sử dụng tất cả CPU trên máy chủ cơ sở dữ liệu.

1

Tôi cũng nghĩ rằng bảng tạm thời có thể là giải pháp tốt nhất.

Nếu bạn đã thực hiện "xóa từ .. trong đó ID trong (chọn id từ ...)" thì vẫn có thể chậm với các truy vấn lớn.Do đó, tôi khuyên bạn nên xóa bằng cách sử dụng kết nối - nhiều người không biết về chức năng đó.

Vì vậy, cho ví dụ này bảng:

-- set up tables for this example 
    if exists (select id from sysobjects where name = 'OurTable' and type = 'U') 
     drop table OurTable 
    go 

    create table OurTable (ID integer primary key not null) 
    go 
    insert into OurTable (ID) values (1) 
    insert into OurTable (ID) values (2) 
    insert into OurTable (ID) values (3) 
    insert into OurTable (ID) values (4) 
    go 

Sau đó chúng tôi có thể viết mã xóa của chúng tôi như sau:

create table #IDsToDelete (ID integer not null) 
    go 
    insert into #IDsToDelete (ID) values (2) 
    insert into #IDsToDelete (ID) values (3) 
    go 
    -- ... etc ... 
    -- Now do the delete - notice that we aren't using 'from' 
    -- in the usual place for this delete 
    delete OurTable from #IDsToDelete 
     where OurTable.ID = #IDsToDelete.ID 
    go 
    drop table #IDsToDelete 
    go 
    -- This returns only items 1 and 4 
    select * from OurTable order by ID 
    go 
+0

+1 để đưa ra ví dụ về việc xóa sử dụng tempdb để không giữ áp phích ban đầu đoán cách thực hiện –