2009-07-20 35 views
10

Tôi muốn thay đổi một trường từ một bảng có khoảng 4 triệu bản ghi. Tôi đảm bảo rằng tất cả các giá trị của các trường này là NOT NULL và muốn ALTER trường này thành NOT NULLTrường ALTER SQL Server NOT NULL mất mãi

ALTER TABLE dbo.MyTable 
ALTER COLUMN myColumn int NOT NULL 

... dường như mất vĩnh viễn để thực hiện cập nhật này. Bất kỳ cách nào để tăng tốc độ hoặc tôi bị mắc kẹt chỉ làm việc đó qua đêm trong giờ làm việc?

Điều này cũng có thể gây ra khóa bàn không?

+1

Cá nhân tôi sẽ không bao giờ làm cho một sự thay đổi cấu trúc bảng trong một bảng lớn hiện bất cứ lúc nào, trừ giờ cao điểm.Ngay cả khi nó là khá nhanh, nó có thể gây ra người dùng trong quá trình làm những việc ở momment bạn thực hiện thay đổi để có vấn đề. Mọi thay đổi lớn đều được thực hiện tốt nhất ở chế độ người dùng đơn. Tốt hơn hết là có thời gian bảo trì theo lịch trình bị bôi đen khi người dùng không thể làm bất cứ điều gì (được thông báo trước và trong giờ cao điểm), hơn là có những người dùng không hài lòng đang làm việc gì đó đang gặp lỗi. – HLGEM

+0

Cột bạn đang thay đổi có liên quan đến các ràng buộc FK không? – onupdatecascade

+1

Từ một bài kiểm tra nhanh trong profiler, nó có một khóa 'Sch-M' trên bảng [về cơ bản là không tương thích với mọi thứ] (http://msdn.microsoft.com/en-us/library/ms186396.aspx). Sau đó nó phải đọc mọi trang để xác định rằng tất cả các hàng xác nhận. –

Trả lời

4

Bạn có thể thay đổi trường và làm cho trường đó không rỗng mà không kiểm tra trường. Nếu bạn thực sự lo lắng về việc không làm nó ra khỏi giờ, bạn có thể thêm một ràng buộc vào lĩnh vực mà kiểm tra để đảm bảo nó không phải là null để thay thế. Điều này sẽ cho phép bạn sử dụng tùy chọn không có kiểm tra và không kiểm tra từng hàng trong số 4 triệu hàng để xem liệu nó có cập nhật hay không.

CREATE TABLE Test 
(
    T0 INT Not NULL, 
    T1 INT NUll 
) 

INSERT INTO Test VALUES(1, NULL) -- Works! 

ALTER TABLE Test 
    WITH NOCHECK 
     ADD CONSTRAINT N_null_test CHECK (T1 IS NOT NULL) 

    ALTER COLUMN T1 int NOT NULL 

INSERT INTO Test VALUES(1, NULL) -- Doesn't work now! 

Thực sự bạn có hai lựa chọn (thêm một phần ba thấy chỉnh sửa):

  1. Sử dụng các hạn chế đó sẽ ngăn chặn bất kỳ hàng mới được cập nhật và để lại những bản gốc không thay đổi gì.
  2. Cập nhật các hàng không có gì khác và sau đó áp dụng tùy chọn không thay đổi null. Điều này thực sự nên được chạy trong giờ tắt, trừ khi bạn không nhớ các quá trình đang bị khóa khỏi bảng.

Tùy thuộc vào tình huống cụ thể của bạn, tùy chọn có thể tốt hơn cho bạn. Tôi sẽ không chọn tùy chọn bởi vì bạn phải chạy nó trong giờ tắt. Về lâu dài, thời gian bạn dành cho việc cập nhật vào giữa đêm sẽ được chi tiêu tốt so với những cơn đau đầu bạn có thể phải đối mặt bằng cách cắt ngắn để tiết kiệm một vài giờ.

Tất cả điều này được nói, nếu bạn định sử dụng tùy chọn hai, bạn có thể giảm thiểu số lượng công việc bạn làm trong giờ làm việc. Vì bạn phải chắc chắn rằng bạn cập nhật các hàng không null trước khi thay đổi cột, bạn có thể viết một con trỏ đến chậm (so với làm việc đó tất cả cùng một lúc)

  1. Đi qua mỗi hàng
  2. Kiểm tra xem nếu nó là null
  3. Cập nhật nó một cách thích hợp. Quá trình này sẽ mất nhiều thời gian, nhưng nó sẽ không khóa toàn bộ các khối chương trình khác truy cập vào nó. (Đừng quên gợi ý with(rowlock) bảng!)

EDIT: Tôi chỉ nghĩ đến một lựa chọn thứ ba: Bạn có thể tạo một bảng mới với các cột thích hợp, và sau đó xuất dữ liệu từ bảng gốc cái mới. Khi điều này được thực hiện, sau đó bạn có thể thả bảng gốc và thay đổi tên của cái mới thành cái cũ. Để làm điều này, bạn sẽ phải vô hiệu hóa các phụ thuộc trên bản gốc và thiết lập chúng trở lại trên một cái mới khi bạn đã làm xong, nhưng quá trình này sẽ làm giảm đáng kể số lượng công việc bạn phải làm trong những giờ nghỉ. Đây là cách tiếp cận tương tự mà máy chủ sql sử dụng khi bạn thực hiện thay đổi thứ tự cột cho bảng thông qua studio quản lý. Đối với phương pháp này, tôi sẽ thực hiện việc chèn vào các khối để đảm bảo rằng bạn không gây ra sự căng thẳng hoàn toàn trên hệ thống và ngăn người khác truy cập vào nó. Sau đó, vào giờ tắt, bạn có thể thả bản gốc, đổi tên phần thứ hai, và áp dụng các phụ thuộc, vv Bạn vẫn sẽ có một số giờ làm việc, nhưng nó sẽ nhỏ hơn so với cách tiếp cận khác.

Liên kết đến sử dụng sp_rename.

+4

Nếu bạn sử dụng KHÔNG KIỂM TRA, thì ràng buộc sẽ không được tin cậy và không thể được sử dụng bởi trình tối ưu hóa truy vấn. Xem http://sqlblog.com/blogs/tibor_karaszi/archive/2008/01/12/non-trusted-constraints-and-performance.aspx –

+3

Ngoài ra, từ khóa NOCHECK không áp dụng cho NULL/NOT NULL. Nó chỉ áp dụng cho các ràng buộc là một phần của mệnh đề CONSTRAINT. –

+0

Từ câu hỏi, OP đã đảm bảo rằng cột của họ không chứa bất kỳ giá trị 'NULL' nào để không chắc chắn về mức độ liên quan của phần 2 trong câu trả lời của bạn? –

2

Xin lỗi vì sự chán nản, nhưng:

  • Bất kỳ cách để tăng tốc độ nó lên: Không, không phải nếu bạn muốn thay đổi cấu trúc bảng tự
  • hay tôi bị mắc kẹt chỉ làm việc đó qua đêm trong off- giờ? Có, và đó có thể là tốt nhất vì @HLGEM đã chỉ ra
  • Điều này cũng có thể gây ra khóa bàn? Có

Không có liên quan trực tiếp cho bạn (vì nó về đi từ NOT NULL NULL), nhưng thú vị đọc về chủ đề này: http://beyondrelational.com/blogs/sankarreddy/archive/2011/04/05/is-alter-table-alter-column-not-null-to-null-always-expensive.aspx

Và cuối cùng một số lịch sử cổ đại - về một câu hỏi tương đương trong một diễn đàn trong Năm 2005, đề nghị tương tự đã được thực hiện như @Kevin cung cấp ở trên - sử dụng một hạn chế insteadof làm cột riêng của mình không nullable: http://www.sqlteam.com/Forums/topic.asp?TOPIC_ID=50671

4

cách duy nhất để làm điều này "nhanh chóng" (*) mà tôi biết là bởi

  • tạo bảng 'bóng' có bố cục bắt buộc
  • thêm trình kích hoạt vào bảng nguồn để bất kỳ thao tác chèn/cập nhật/xóa nào được sao chép vào bảng bóng (để bắt bất kỳ NULL nào có thể bật lên!)
  • sao chép tất cả dữ liệu từ nguồn vào bảng bóng, có khả năng trong các khối nhỏ (đảm bảo bạn có thể xử lý dữ liệu đã được sao chép bằng trình kích hoạt), đảm bảo dữ liệu sẽ phù hợp với cấu trúc mới (ISNULL (?))
  • kịch bản ra tất cả phụ thuộc từ/đến các bảng khác
  • khi tất cả được thực hiện, làm như sau bên trong một giao dịch rõ ràng:
    • nhận được một khóa bảng độc quyền trên nguồn bảng và một trên shadowtable
    • chạy các script để thả phụ thuộc vào nguồn bảng
    • đổi tên nguồn bảng để cái gì khác (ví dụ hậu tố _old)
    • đổi tên bảng bóng tối để tên gốc nguồn của bảng
    • chạy các kịch bản để tạo ra tất cả các phụ thuộc một lần nữa

Bạn có thể muốn làm bước cuối cùng bên ngoài của giao dịch một Có thể mất khá nhiều thời gian tùy thuộc vào số lượng và kích thước của các bảng tham chiếu đến bảng này, các bước đầu tiên sẽ không mất nhiều thời gian ở tất cả

Như thường lệ, có lẽ tốt nhất là chạy thử nghiệm -server first =)

PS: xin vui lòng không bị cám dỗ để tạo lại FK với NOCHECK, nó làm cho chúng vô ích vì trình tối ưu hóa sẽ không tin tưởng chúng cũng như không xem xét khi xây dựng kế hoạch truy vấn.

(*: nơi nhanh chóng đi xuống đến: với thời gian chết ít nhất có thể)

+0

Tôi đã từng đùa giỡn với ý tưởng này trong tuần qua, nhưng trong tình huống cụ thể của chúng tôi, chúng tôi thấy vấn đề vì có thể có nhiều thay đổi cột không biết về nhau, do đó việc tạo động "thay vì" sẽ không thể thực hiện được (đây là tất cả để được tự động). Sáng nay nó xảy ra với tôi rằng nó có thể được bảng điều khiển và tôi sẽ đăng câu trả lời ở đây chỉ để thấy rằng bạn đánh bại tôi với nó :) –

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