2009-08-13 27 views
45

Nói rằng tôi có một bảng đơn giản mà có các lĩnh vực sau:Trong SQL, UPDATE có luôn nhanh hơn DELETE + INSERT không?

  1. ID: int, autoincremental (sắc), tiểu học then chốt
  2. Tên: varchar (50), độc đáo, có chỉ số duy nhất
  3. Tag : int

Tôi không bao giờ sử dụng trường ID để tra cứu, vì ứng dụng của tôi luôn dựa trên hoạt động với trường Tên.

Tôi cần thay đổi giá trị Thẻ theo thời gian. Tôi đang sử dụng mã SQL tầm thường như sau:

UPDATE Table SET Tag = XX WHERE Name = YY; 

Tôi tự hỏi nếu có ai biết cho dù là ở trên luôn nhanh hơn:

DELETE FROM Table WHERE Name = YY; 
INSERT INTO Table (Name, Tag) VALUES (YY, XX); 

Một lần nữa - Tôi biết rằng trong ví dụ thứ hai ID được thay đổi , nhưng nó không quan trọng cho ứng dụng của tôi.

+10

là một thực tế, tôi không bao giờ khuyên bạn nên cập nhật cột khóa chính. –

+0

@KM: Tôi đồng ý, đây là cách đơn giản hóa bảng thực sự của tôi, nơi tất cả tra cứu được thực hiện trên một trường chuỗi duy nhất không phải là khóa chính. Tôi có một giá trị int khóa chính hoàn toàn không liên quan nên tôi đã xóa nó khỏi ví dụ (nó được tạo tự động và không tham gia tra cứu) –

+0

@KM: Tôi đã cập nhật ví dụ để phản ánh cấu trúc bảng thực, chỉ trong trường hợp nó tạo ra sự khác biệt. –

Trả lời

12

Một lệnh trên cùng một hàng phải luôn nhanh hơn hai trên cùng một hàng. Vì vậy, UPDATE chỉ sẽ tốt hơn.

EDIT thiết lập bảng:

create table YourTable 
(YourName varchar(50) primary key 
,Tag int 
) 

insert into YourTable values ('first value',1) 

hoạt động này, trong đó có 1 giây trên hệ thống của tôi (SQL Server 2005):

SET NOCOUNT ON 
declare @x int 
declare @y int 
select @x=0,@y=0 
UPDATE YourTable set YourName='new name' 
while @x<10000 
begin 
    Set @[email protected]+1 
    update YourTable set YourName='new name' where YourName='new name' 
    SET @[email protected][email protected]@ROWCOUNT 
end 
print @y 

hoạt động này, mà mất 2 giây trên hệ thống của tôi:

SET NOCOUNT ON 
declare @x int 
declare @y int 
select @x=0,@y=0 
while @x<10000 
begin 
    Set @[email protected]+1 
    DELETE YourTable WHERE YourName='new name' 
    insert into YourTable values ('new name',1) 
    SET @[email protected][email protected]@ROWCOUNT 
end 
print @y 
+4

Bạn có dựa trên bất kỳ dữ liệu cụ thể nào không? –

+0

@Rax Olgud, bạn trả lời như thế nào? Bạn thậm chí không nói cơ sở dữ liệu bạn đang sử dụng. Bạn đã hỏi một câu hỏi khái niệm, nhưng vẫn muốn có dữ liệu cụ thể.Nếu bạn muốn dữ liệu thực tế sau đó bạn sẽ cần phải viết một vòng lặp wile (trên hệ thống của bạn), và cập nhật hàng 1000 lần, viết một vòng lặp mà sẽ xóa/chèn nó 1000 lần. và xem cái gì nhanh hơn. –

+2

@Rax Olgud, có một số chi phí trong việc loại bỏ và tạo ra một giá trị chỉ mục và kiểm tra bất kỳ ràng buộc nào. nếu bạn chỉ cập nhật một cột dữ liệu, nó sẽ tránh được bất kỳ chi phí nào. –

2

Rõ ràng là câu trả lời khác nhau dựa trên cơ sở dữ liệu bạn đang sử dụng, nhưng UPDATE luôn có thể được triển khai nhanh hơn DELETE + INSERT. Vì các ops trong bộ nhớ hầu hết là tầm thường, dựa trên cơ sở dữ liệu dựa trên ổ cứng, một UPDATE có thể thay đổi một trường cơ sở dữ liệu tại vị trí trên hdd, trong khi xóa sẽ xóa một hàng (để trống một khoảng trống) và chèn mới hàng, có lẽ đến cuối bảng (một lần nữa, đó là tất cả trong việc thực hiện).

Khác, nhỏ, vấn đề là khi bạn CẬP NHẬT một biến duy nhất trong một hàng, các cột khác trong hàng đó vẫn giữ nguyên. Nếu bạn DELETE và sau đó thực hiện INSERT, bạn có nguy cơ quên đi các cột khác và do đó để chúng bị bỏ lại (trong trường hợp này bạn sẽ phải thực hiện lệnh SELECT trước khi DELETE lưu tạm thời các cột khác của bạn trước khi viết lại bằng INSERT) .

+1

Tôi không chắc chắn tôi đồng ý với bạn về điểm đầu tiên, đặc biệt là khi sử dụng các loại chuỗi có độ dài thay đổi. Việc cập nhật những thứ đó thực sự có thể yêu cầu ghi HD ở "địa điểm mới". –

+0

Cũng trên các chỉ mục DELETE + INSERT phải được cập nhật hai lần. –

+0

@Rax từ khóa "có thể" – erjiang

4

Hãy nhớ rằng sự phân mảnh thực sự xảy ra khi DELETE + INSERT được phát hành trái ngược với một UPDATE được triển khai chính xác sẽ tạo sự khác biệt lớn theo thời gian.

Đó là lý do tại sao, ví dụ, REPLACE INTO thực hiện MySQL không được khuyến khích như trái ngược với việc sử dụng cú pháp INSERT INTO ... ON DUPLICATE KEY UPDATE ....

3

Trong trường hợp của bạn, tôi tin rằng bản cập nhật sẽ nhanh hơn.

Ghi chỉ mục!

Bạn đã xác định khóa chính, nó có khả năng sẽ tự động trở thành chỉ mục được nhóm (ít nhất là SQL Server làm như vậy). Một chỉ số cụm có nghĩa là các bản ghi được đặt trên đĩa vật lý theo chỉ mục. Thao tác DELETE sẽ không gây ra nhiều rắc rối, ngay cả sau khi một bản ghi biến mất, chỉ mục vẫn chính xác. Nhưng khi bạn INSERT một kỷ lục mới, các công cụ DB sẽ phải đặt bản ghi này ở vị trí chính xác mà trong hoàn cảnh sẽ gây ra một số "reshuffling" của các hồ sơ cũ để "làm cho" cho một cái mới. Có nơi nó sẽ làm chậm hoạt động.

Chỉ mục (đặc biệt là nhóm) hoạt động tốt nhất nếu các giá trị ngày càng tăng, vì vậy các bản ghi mới chỉ được nối vào đuôi. Có lẽ bạn có thể thêm một cột INT IDENTITY để trở thành một chỉ số nhóm, điều này sẽ đơn giản hóa các hoạt động chèn.

+1

Việc 'thay đổi lại' sẽ có sự phân chia trang. – Andrew

1

Nó phụ thuộc vào sản phẩm. Một sản phẩm có thể được triển khai thực hiện (bên dưới nắp) chuyển đổi tất cả các UPDATE thành DELETE và INSERT (được bao bọc giao dịch). Cung cấp kết quả phù hợp với ngữ nghĩa UPDATE.

Tôi không nói rằng tôi biết về bất kỳ sản phẩm nào thực hiện điều này, nhưng nó hoàn toàn hợp pháp.

+0

... hoàn toàn hợp pháp, miễn là kiểm tra ràng buộc khóa ngoài được hoãn lại cho đến sau khi chèn, có thể không hợp pháp. –

+0

Tôi không chắc chắn nhưng tôi đã nghe nói rằng SQL Server thực hiện một DELETE + INSERT cho UPDATE, nội bộ. Nếu đúng như vậy, nó sẽ tạo ra bất kỳ sự khác biệt nào trong trường hợp SQL Server? – Faiz

+0

@Faiz - giống như mọi thứ, cách duy nhất để chắc chắn là kiểm tra dữ liệu của bạn, trong môi trường của bạn. Chi phí cơ bản của các hoạt động này dường như không phải là nút cổ chai của bạn - bao giờ hết. Với SQL Server, nếu bạn đã có một trigger, nó chắc chắn * giống như * một xóa/chèn, nhưng cho dù đó là những gì hệ thống thực sự làm, những người cần biết :-) –

25

Bảng lớn hơn (số lượng và kích thước cột) càng tốn kém để xóa và chèn thay vì cập nhật. Bởi vì bạn phải trả giá của UNDO và REDO. DELETE tiêu thụ nhiều không gian hơn UNDO so với UPDATE và REDO của bạn chứa nhiều câu lệnh gấp hai lần nếu cần.

Bên cạnh đó, điều này hoàn toàn sai so với quan điểm kinh doanh. Hãy xem xét sẽ khó khăn hơn bao nhiêu để hiểu một đường mòn kiểm toán không chính thức trên bảng đó.


Có một số tình huống liên quan đến cập nhật số lượng lớn của tất cả các hàng trong một bảng, nơi nó là nhanh hơn để tạo ra một bảng mới sử dụng CTAS từ bảng cũ (áp dụng bản cập nhật trong các dự báo của mệnh đề SELECT), thả bảng cũ và đổi tên bảng mới. Các tác dụng phụ là tạo ra các chỉ mục, quản lý các ràng buộc và gia hạn các đặc quyền, nhưng nó đáng xem xét.

1

Mọi ghi vào cơ sở dữ liệu đều có nhiều tác dụng phụ tiềm ẩn.

Xóa: phải xóa hàng, chỉ mục được cập nhật, khóa ngoại và có thể bị xóa, v.v. Chèn: hàng phải được cấp - điều này có thể thay cho hàng đã xóa, có thể không được; chỉ mục phải được cập nhật, kiểm tra khóa ngoài, v.v. Cập nhật: phải cập nhật một hoặc nhiều giá trị; có lẽ dữ liệu của hàng không còn phù hợp với khối cơ sở dữ liệu đó nữa, do đó phải phân bổ nhiều không gian hơn, có thể xếp vào nhiều khối được viết lại hoặc dẫn đến các khối bị phân mảnh; nếu giá trị có các ràng buộc khóa ngoài, chúng phải được kiểm tra, v.v.

Đối với một số cột rất nhỏ hoặc nếu toàn bộ hàng được cập nhật Xóa + chèn có thể nhanh hơn, nhưng vấn đề ràng buộc FK là một vấn đề lớn. Chắc chắn, có thể bạn không có ràng buộc FK bây giờ, nhưng điều đó luôn luôn đúng? Và nếu bạn có một kích hoạt, nó dễ dàng hơn để viết mã xử lý các bản cập nhật nếu hoạt động cập nhật thực sự là một bản cập nhật.

Một vấn đề khác cần suy nghĩ là đôi khi việc chèn và xóa giữ các khóa khác với việc cập nhật. DB có thể khóa toàn bộ bảng trong khi bạn đang chèn hoặc xóa, thay vì chỉ khóa một bản ghi trong khi bạn đang cập nhật bản ghi đó.

Cuối cùng, tôi khuyên bạn chỉ nên cập nhật một bản ghi nếu bạn muốn cập nhật nó. Sau đó, kiểm tra thống kê hiệu suất của DB và thống kê cho bảng đó để xem có cải thiện hiệu suất nào không. Bất cứ điều gì khác là quá sớm.

Ví dụ từ hệ thống thương mại điện tử tôi làm việc: Chúng tôi đã lưu trữ dữ liệu giao dịch thẻ tín dụng trong cơ sở dữ liệu theo cách tiếp cận hai bước: đầu tiên, viết một phần giao dịch để cho biết rằng chúng tôi đã bắt đầu quá trình. Sau đó, khi dữ liệu ủy quyền được trả về từ ngân hàng, hãy cập nhật hồ sơ. Chúng tôi đã xóa rồi chèn lại bản ghi nhưng thay vào đó chúng tôi chỉ sử dụng bản cập nhật. DBA của chúng tôi nói với chúng tôi rằng bảng đã bị phân mảnh vì DB chỉ phân bổ một lượng nhỏ không gian cho mỗi hàng và bản cập nhật đã gây ra khối chuỗi vì nó đã thêm nhiều dữ liệu. Tuy nhiên, thay vì chuyển sang DELETE + INSERT, chúng tôi chỉ điều chỉnh cơ sở dữ liệu để luôn phân bổ toàn bộ hàng, điều này có nghĩa là bản cập nhật có thể sử dụng không gian trống được phân bổ trước mà không có vấn đề gì. Không cần thay đổi mã và mã vẫn đơn giản và dễ hiểu.

5

Chỉ cần thử cập nhật 43 trường trên một bảng có 44 trường, trường còn lại là khóa được nhóm chính.

Bản cập nhật mất 8 giây.

Xóa + Chèn nhanh hơn khoảng thời gian tối thiểu mà "Thống kê khách hàng" báo cáo qua SQL Management Studio.

Peter

MS SQL 2008

8

tôi sợ cơ thể của câu hỏi của bạn không liên quan đến câu hỏi tiêu đề.

Nếu để trả lời tiêu đề:

Trong SQL, là CẬP NHẬT luôn nhanh hơn DELETE + INSERT?

thì câu trả lời là KHÔNG!

Chỉ cần google cho

  • "Đắt cập nhật trực tiếp" * "sql server"
  • "cập nhật chậm" * "sql server"

cập nhật như vậy (s) kết quả trong tốn kém hơn (xử lý nhiều hơn) thực hiện cập nhật thông qua chèn + cập nhật hơn chèn trực tiếp + cập nhật. Đây là những trường hợp khi

  • một cập nhật lĩnh vực này với khóa duy nhất (hoặc tiểu học) hoặc
  • khi dữ liệu mới không phù hợp (lớn) trong không gian hàng trước bản cập nhật được phân bổ (hoặc thậm chí hàng tối đa kích thước), dẫn đến phân mảnh,
  • v.v.

nhanh (chưa đầy đủ) tìm kiếm của tôi, không phải giả vờ để được bao gồm một, đã cho tôi [1], [2]

[1] Cập nhật hoạt động
(Performance
Sybase® SQL Server và Tuning Hướng dẫn
Chương 7: Tối ưu hóa SQL server Query)
http://www.lcard.ru/~nail/sybase/perf/11500.htm
[2]
báo cáo cập nhật có thể được nhân rộng như cặp DELETE/INSERT
http://support.microsoft.com/kb/238254

1

Câu hỏi về tốc độ không liên quan nếu không có sự cố tốc độ cụ thể.

Nếu bạn đang viết mã SQL để thực hiện thay đổi cho hàng hiện tại, bạn CẬP NHẬT nó. Bất cứ điều gì khác là không chính xác.

Nếu bạn định phá vỡ các quy tắc về cách mã hoạt động, thì bạn nên có một lý do tốt, được định lượng cho nó, và không phải là một ý tưởng mơ hồ về "Cách này nhanh hơn", khi bạn không 't có bất kỳ ý tưởng những gì "nhanh hơn" là.

3

Nếu bạn có vài triệu hàng. Mỗi hàng bắt đầu với một phần dữ liệu, có thể là tên khách hàng. Khi bạn thu thập dữ liệu cho khách hàng, các mục nhập của họ phải được cập nhật. Bây giờ, giả sử rằng việc thu thập dữ liệu khách hàng được phân phối trên nhiều máy khác mà từ đó nó được thu thập và đưa vào cơ sở dữ liệu sau đó. Nếu mỗi khách hàng có thông tin duy nhất, thì bạn sẽ không thể thực hiện cập nhật hàng loạt; tức là, không có tiêu chí điều khoản nào để bạn sử dụng để cập nhật nhiều khách hàng trong một lần chụp. Mặt khác, bạn có thể thực hiện chèn số lượng lớn. Vì vậy, câu hỏi có thể được đặt ra tốt hơn như sau: Có tốt hơn khi thực hiện hàng triệu bản cập nhật đơn lẻ hay tốt hơn là biên dịch chúng thành các lần xóa và chèn hàng loạt lớn. Nói cách khác, thay vì "cập nhật [bảng] đặt trường = dữ liệu trong đó clientid = 123" một lần milltion, bạn thực hiện 'xóa từ [bảng] trong đó clientid trong ([tất cả các máy khách được cập nhật]); chèn vào [bảng] các giá trị (dữ liệu cho client1), (dữ liệu cho client2), vv '

Hoặc là lựa chọn tốt hơn so với dữ liệu khác, hoặc bạn có phải là cả hai cách?

0

Trong trường hợp cụ thể, Xóa + Chèn sẽ tiết kiệm thời gian cho bạn. Tôi có một bảng có 30000 hàng lẻ và có một bản cập nhật/chèn hàng ngày của các bản ghi này bằng cách sử dụng tệp dữ liệu. Quá trình tải lên tạo ra 95% báo cáo cập nhật vì các bản ghi đã có và 5% chèn cho các bản ghi không tồn tại. Ngoài ra, tải lên các hồ sơ tập tin dữ liệu vào một bảng tạm thời, xóa bảng đích cho các bản ghi trong bảng tạm thời theo sau là chèn cùng một từ bảng tạm thời đã cho thấy 50% đạt được trong thời gian.

5

Xóa + Chèn hầu như luôn luôn nhanh hơn vì Bản cập nhật có nhiều bước liên quan hơn.

Cập nhật:

  1. Look cho hàng sử dụng PK.
  2. Đọc hàng từ đĩa.
  3. Kiểm tra mà giá trị đã thay đổi
  4. Nâng onUpdate Kích hoạt với dân cư: NEW và: biến OLD
  5. Viết biến mới vào đĩa (Toàn bộ hàng)

    (này lặp lại cho mỗi dòng bạn' tái cập nhật)

Xóa + Insert:

  1. Đánh dấu các hàng là đã xóa (Chỉ trong PK).
  2. Chèn các hàng mới ở cuối bảng.
  3. Cập nhật chỉ mục PK với vị trí của các bản ghi mới.

    (Điều này không lặp lại, tất cả có thể được làm tròn trong một khối hoạt động).

Sử dụng Insert + Delete sẽ phân đoạn Hệ thống tệp của bạn, nhưng không nhanh như vậy. Làm một tối ưu hóa lười biếng trên nền sẽ allways miễn phí khối không sử dụng và đóng gói bảng hoàn toàn.

+5

Câu trả lời này đơn giản hóa các hoạt động và bỏ lỡ một nhiều bước cho các mô hình RDBM thương mại chính - xóa một hàng bằng cách thay đổi PK (và không có gì khác) không phải là cách các RDBM thương mại chính hoạt động. Thông tin của bạn về trình kích hoạt không chính xác và một chiều. Để bắt đầu, việc xóa/chèn có thể/cũng sẽ kích hoạt các trình kích hoạt - nhưng bạn không bao gồm các trình kích hoạt đó. Trừ khi bạn chỉ định kích hoạt mỗi hàng, nó cũng sẽ chỉ kích hoạt một lần cho bản cập nhật và hai lần để xóa/chèn. – Andrew

39

Một chút quá muộn với câu trả lời này, nhưng kể từ khi tôi phải đối mặt với một câu hỏi tương tự, tôi đã thực hiện một thử nghiệm với JMeter và một máy chủ MySQL trên cùng một máy, nơi mà tôi đã sử dụng:

  1. Một điều khiển giao dịch (tạo mẫu cha mẹ) chứa hai Yêu cầu JDBC: một lệnh Xóa và Chèn
  2. Yêu cầu JDBC sepparate có chứa câu lệnh Cập nhật.

Sau khi chạy thử nghiệm cho 500 vòng, tôi đã thu được những kết quả sau đây:

DEL + INSERT - trung bình: 62ms

Cập nhật - trung bình: 30ms

Kết quả: Results

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