2010-04-01 37 views
5

Tôi có một bảng chứa các mục nhập nhật ký cho một chương trình tôi đang viết. Tôi đang tìm kiếm ý tưởng về một truy vấn SQL (Tôi đang sử dụng SQL Server Express 2005) sẽ giữ số lượng bản ghi X mới nhất và xóa phần còn lại. Tôi có một cột datetime là một dấu thời gian cho mục nhập nhật ký.Truy vấn SQL để xóa các hàng cũ nhất trên một số hàng nhất định?

Tôi tìm một số thứ như sau sẽ hoạt động, nhưng tôi không chắc chắn về hiệu suất với mệnh đề IN cho số lượng bản ghi lớn hơn. Hiệu suất không quan trọng, nhưng tôi cũng có thể làm tốt nhất lần đầu tiên.

DELETE FROM MyTable WHERE PrimaryKey NOT IN 
(SELECT TOP 10,000 PrimaryKey FROM MyTable ORDER BY TimeStamp DESC) 

Tôi nên đề cập truy vấn này sẽ chạy 3-4 lần một ngày (như một phần của quá trình khác), vì vậy số lượng hồ sơ sẽ bị xóa với mỗi truy vấn sẽ nhỏ so với số lượng hồ sơ sẽ được lưu giữ.

+0

Các bạn đã thử nó? Nó có hoạt động không?NẾU nó không quan trọng, và những gì bạn đã làm việc, là khá rõ ràng những gì đang xảy ra, và là "đủ nhanh" đi với nó. – Nate

+0

Chưa thử, nhưng nó sẽ hoạt động. Tôi thừa nhận tôi có tội về việc tối ưu hóa, đó là một thói quen xấu. –

Trả lời

3

Hãy thử điều này:

DECLARE @X int 
SELECT @X=COUNT(*) FROM MyTable 
SET @[email protected] 

DELETE MyTable 
WHERE PrimaryKey IN (SELECT TOP(@x) PrimaryKey 
        FROM MyTable 
        ORDER BY TimeStamp ASC 
        ) 

loại phụ thuộc vào nếu bạn đang xóa ít hơn 10.000 hàng, nếu có thì điều này có thể chạy nhanh hơn, vì nó xác định các hàng để xóa, không phải là hàng giữ.

1

Truy vấn bạn có về hiệu quả như nó nhận được và có thể đọc được.

NOT INNOT EXISTS hiệu quả hơn LEFT JOIN/IS NULL, nhưng chỉ vì cả hai cột không bao giờ có thể rỗng. Bạn có thể read this link for a more in-depth comparison.

1
DELETE FROM MyTable 
WHERE TimeStamp < (SELECT min(TimeStamp) 
        FROM (SELECT TOP 10,000 TimeStamp 
         FROM MyTable 
         ORDER BY TimeStamp DESC)) 

hoặc

DELETE FROM MyTable 
WHERE TimeStamp < (SELECT min(TimeStamp) 
        FROM MyTable 
        WHERE PrimaryKey IN (SELECT TOP 10,000 TimeStamp 
             FROM MyTable 
             ORDER BY TimeStamp DESC)) 

Không chắc nếu đây là những cải tiến càng xa càng hiệu quả mặc dù.

1

Điều này phụ thuộc vào kịch bản của bạn (cho dù đó là khả thi đối với bạn) và số lượng hàng bạn có, nhưng có một cách tiếp cận tối ưu tiềm năng hơn nhiều.

  1. Tạo một bản sao mới của bảng đăng nhập với một tên mới
  2. Chèn vào bảng mới, 10.000 hồ sơ gần đây nhất từ ​​bảng gốc
  3. Drop bảng gốc (hoặc đổi tên)
  4. Đổi tên bảng mới thành tên thích hợp

Điều này rõ ràng đòi hỏi nhiều hơn là chỉ xóa các hàng (ví dụ: nếu bảng có cột IDENTITY cần được đặt trên bảng mới, v.v.). Nhưng nếu bạn có một bảng lớn thì sẽ hiệu quả hơn khi sao chép 10.000 hàng vào một bảng mới, sau đó thả bảng gốc, hơn là cố gắng xóa hàng triệu hàng chỉ còn lại 10.000.

2

Hãy thử điều này, sử dụng CTE để lấy số thứ tự hàng, và sau đó chỉ xóa số hàng X tại một thời điểm. Bạn có thể thay đổi biến này cho phù hợp với máy chủ của bạn.

Thêm gợi ý bảng ReadPast sẽ ngăn chặn khóa.

:

DECLARE @numberToDelete INT; 
DECLARE @ROWSTOKEEP INT; 
SET @ROWSTOKEEP = 50000; 
SET @numberToDelete =1000; 

WHILE 1=1 
BEGIN 
    WITH ROWSTODELETE AS 
    (
     SELECT ROW_NUMBER() OVER(ORDER BY dtsTimeStamp DESC) rn, 
      * 
     FROM MyTable 

    ) 
    DELETE TOP (@numberToDelete) FROM ROWSTODELETE WITH(READPAST) 
    WHERE rn>@ROWSTOKEEP; 

    IF @@ROWCOUNT=0 
     BREAK; 
END; 
Các vấn đề liên quan