Cách hiệu quả để thay đổi các trường VARCHAR thành NVARCHAR trong một bảng lớn trong SQL Server 2008?


7

Tôi biết khi thêm các trường mới vào các bảng lớn, nên thêm chúng vào cuối các trường thay vì ở đâu đó ở giữa và tự hỏi liệu điều gì đó như thế này có áp dụng khi thay đổi loại trường không?

Tôi có một bảng với khoảng một triệu bản ghi có nhiều trường loại VARCHAR. Tôi muốn thay đổi chúng thành NVARCHAR, nhưng theo tôi hiểu, việc này sẽ mất một chút thời gian và tài nguyên, vì các trường nằm ở giữa bảng và SQL Server phải thực hiện một loạt sao chép / sắp xếp lại.

Một cách hiệu quả để thực hiện điều này là gì?


2
Đây có phải là một nỗ lực để làm cho cơ sở dữ liệu quốc tế hóa? Vì các khóa chỉ mục của bạn sẽ tăng gấp đôi (AFAIR, NVARCHAR dành gấp đôi dung lượng lưu trữ của các trường varchar) và nếu bạn có khóa chỉ mục đặc biệt dài, có thể tạo khóa không thể được xây dựng lại (khóa chỉ mục được giới hạn ở 900 byte, AFAIR )
Fabricio Araujo

Và nó sẽ đánh thuế hệ thống con I / O của bạn nếu bảng đó thực sự lớn (ví dụ: một bảng có 1M hàng với cột varchar với chuỗi có kích thước trung bình là 40 ký tự. Với varchar bạn sẽ có một bảng có 36Mb dữ liệu char, với nvarchar, dữ liệu tương tự sẽ cần 76Mb để được lưu trữ / đọc / ghi).
Fabricio Araujo

Thảo luận tuyệt vời, và cảm ơn bạn cho cái nhìn sâu sắc. Thông tin về chỉ mục và kích thước với nvarchar là hữu ích nhất. Có phải việc sử dụng nvarchar sẽ phát sinh thêm lượt truy cập hiệu suất trên varchar không?
ElHaix

3
@FovenioAraujo: Đừng làm hỏng chủ đề này. varchar vs nvarchar được thảo luận ở đây stackoverflow.com/a/198753/27535 . int vs smallint: dba.stackexchange.com/a/4979/630 . OP đã hỏi về việc thay đổi các lĩnh vực: trả lời điều đó và cho rằng OP biết những gì và tại sao anh ta muốn làm điều này. Trên cấu trúc đĩa? sqlskills.com/bloss/paul/post/ từ
gbn

1
@ElHaix: Tôi nhớ bạn bình luận trong tất cả các tiếng ồn. Vui lòng xem stackoverflow.com/questions353366/ diệt nvarchar có một chi phí đáng kể trên tất cả các khía cạnh so với varchar. Nói rằng, nếu bạn có dữ liệu unicode, hãy sử dụng nvarchar. Đừng hack một cái gì đó cùng nhau để giải quyết vấn đề này
gbn

Câu trả lời:


7

Trả lời trực tiếp câu hỏi, có hai cách để thực hiện thao tác.

  • Nếu số lượng cột varchar liên quan trên bảng là nhỏ (một hoặc hai), thì việc tạo các cột giả tạm thời sẽ thực tế hơn
  • Nếu số lượng cột varchar lớn hơn, cách trên không thực tế lắm - vì vậy bạn tạo một bảng giả. Điều này được sử dụng nhiều nhất trên các tập lệnh cập nhật siêu dữ liệu của một số công cụ cơ sở dữ liệu như ErWin hoặc ER / Studio (Tôi đã sử dụng cả hai công cụ và xem lại các tập lệnh được tạo trước khi áp dụng)

Lưu ý trên các bảng lớn : Nếu bảng có vài nghìn bản ghi hoặc ít hơn, bạn có thể thực hiện thao tác cùng một lúc. Trong trường hợp bảng triệu bản ghi, sẽ thực tế hơn khi thực hiện theo lô (giả sử 1000 hoặc 100 bản ghi mỗi lần).

Cột giả

Các cột giả tạm thời (tôi quên nếu có tên khác, tên thích hợp hơn) là các cột được sử dụng để lưu trữ kết quả của chuyển đổi. Trong trường hợp này, chúng cũng sẽ là cột cuối cùng sau quá trình.

  1. Tạo các cột mới với chiều dài dự định. Đừng quên bao gồm bất kỳ ràng buộc kiểm tra hoặc mặc định nào cho định nghĩa mới
  2. Thực hiện cập nhật (hoặc cập nhật, xem quan sát ở trên) để lưu trữ dữ liệu của cột cũ trong cột mới.
  3. Thực hiện sao lưu nhật ký và thực hiện kiểm tra, để không cho phép nhật ký phát triển lớn một cách vô lý.
  4. Nếu cột cũ có bất kỳ ràng buộc nào liên quan đến nó, hãy bỏ chúng.
  5. Thả cột cũ.
  6. Đổi tên cột mới thành tên cột cũ
  7. Xây dựng lại các chỉ mục bị ảnh hưởng (hoặc tất cả, nếu cột bị ảnh hưởng cũng là một phần của ràng buộc khóa chính cụm - hiếm khi ai đó sử dụng varar (n) làm PK, nhưng tôi đã thấy một số).

Đây là quá trình tương tự chi tiết trong câu trả lời của Aaron .

Bảng giả

Khi sửa đổi trong nhiều hơn một số cột, sẽ thực tế hơn khi tạo một bảng mới, dựa trên lược đồ của bảng cũ.

  1. Tạo một bảng mới, không có bất kỳ ràng buộc bảng nào (PK, FK, v.v.). Chỉ mang theo những cột tại thời điểm này (KHÔNG phải NULL, DEFAULT, KIỂM TRA, v.v.)
  2. Chèn dữ liệu vào bảng cũ trong bảng mới (xem Ghi chú trên các bảng lớn ở trên). SET IDENTITY_INSERT ở đây là bắt buộc.
  3. Bây giờ, bỏ tất cả các ràng buộc bảng (PK, FK, kiểm tra) và kích hoạt trên bảng cũ. Tái tạo các ràng buộc và kích hoạt trên bảng mới.
  4. Tái tạo tất cả các chỉ mục khác (tất cả cùng một lúc hoặc một lần, tùy thuộc vào cửa sổ bảo trì của bạn) của bảng cũ, trên bảng mới. Trừ khi bảng không có chỉ mục cụm, điều này phải được thực hiện sau bước 3. Hoặc, ít nhất, sau khi tạo ràng buộc PK.
  5. Kiểm tra xem mọi thứ đã ổn chưa (nếu bạn không quên trình kích hoạt hoặc ràng buộc trong quy trình) và, nếu tất cả đều ổn, hãy bỏ bảng cũ.
  6. Đổi tên bảng mới thành tên trên bảng cũ

Lưu ý ở bước 4 : Nếu bạn có bất kỳ chỉ mục trùng lặp nào được phát hiện (phát hiện các chỉ mục trùng lặp là một chủ đề rất dài, hãy xem blog của Kimberly Tripp trên SQLSkills.com), đó là cơ hội để bạn loại bỏ chúng nếu đó là trường hợp.

Ý nghĩa hiệu suất

Thay đổi từ VARCHAR thành NVARCHAR có một số hàm ý về hiệu suất, ít nhất là đối với bất kỳ Máy chủ SQL nào dưới 2008R2. Đối với SQL 2008 R2, Aaron Bertrand có một số bài đăng trên blog về tính năng nén Unicode - có thể chống lại sự cân bằng khi các cột NVarchar được sử dụng để lưu trữ nội dung có thể được lưu trữ trên các cột VARCHAR. Tôi đã không đọc chúng hoàn toàn vì các bài báo xứng đáng, nhưng chủ đề này rất thú vị.

Các cột NVARCHAR theo thời gian (IOW, trước 2008R2) lưu trữ tất cả các ký tự trong các cột với 2 byte mỗi char. Ví dụ: chuỗi 'MSSQL' sẽ được lưu trữ trong 5 byte trên cột VARCHAR và 10 trên cột NVARCHAR. Do các cột chuỗi không LOB bị giới hạn lưu trữ tối đa 8000 byte , điều đó có nghĩa là VARCHAR có thể lưu trữ 8000 ký tự, trong khi NVARCHR bị giới hạn ở 4000.

Ý nghĩa của sự thật đó:

  • Vì các khóa chỉ mục được giới hạn ở 900 byte (xem tài liệu trên CREATE INDEX), nếu bạn cố gắng lập chỉ mục cột NVARCHAR (500), lệnh sẽ không thất bại (nếu đây chỉ là một cột trên khóa chỉ mục), nhưng nếu bạn CẬP NHẬT hoặc XÁC NHẬN một hàng có hơn 450 - (tổng kích thước của các cột khác trên khóa chỉ mục, nếu là trường hợp) các ký tự hoạt động sẽ thất bại.
  • Càng nhiều byte để hoạt động, nhiều việc phải làm. Bạn đọc / ghi / so sánh / bộ nhớ cache gấp đôi byte.
  • Tùy thuộc vào mức độ lớn của bảng, ảnh hưởng của các cột chuỗi đến kích thước được lưu trữ của bảng và mức độ tham gia của bảng trên kích thước cơ sở dữ liệu, bạn có thể mong đợi sự gia tăng về kích thước cơ sở dữ liệu (được sử dụng) và tất cả các biến mà nó ảnh hưởng trực tiếp hoặc không (như thời gian sao lưu / khôi phục, bảo trì chỉ mục, v.v.).

EDIT: như gbn đã nêu, không đáng để tạo ra thứ gì đó chỉ để sử dụng VARCHAR khi bạn có một yêu cầu rõ ràng cần các cột NVARCHAR được điền đầy đủ.


20

Một cách có thể là:

  1. Thêm một cột NVARCHAR NULLable
  2. Sử dụng các lô, cập nhật một số hàng tại một thời điểm (ví dụ: 1000 hoặc 10000 hàng)
  3. Sao lưu nhật ký, điểm kiểm tra, những gì bạn có giữa các đợt
  4. Khi tất cả các hàng đã được cập nhật, bỏ cột cũ và đổi tên cột mới
  5. Xây dựng lại chỉ mục

Điều này sẽ không nhanh hơn trong thời gian dài và vẫn cần một cửa sổ bảo trì (vì bạn không muốn người dùng cập nhật các hàng bạn đã cập nhật trừ khi bạn đặt một trình kích hoạt tạm thời để chống lại điều đó), nhưng nó sẽ ngăn chặn giao dịch lớn và sau một vài cập nhật sẽ cho bạn nhiều dự đoán hơn về việc sẽ mất bao lâu.

Bạn có thể làm điều tương tự bằng cách tạo một bảng mới và đổi tên thành một khi nó đã hoàn thành ... trong khi điều này tránh được sự cần thiết của bước 5, nó sẽ gây ra nhiều rắc rối dữ liệu hơn và có thể gặp nhiều vấn đề hơn do các ràng buộc, khóa ngoại, trình kích hoạt vv có thể liên quan đến bảng.


2
Điểm thưởng cho việc sử dụng các đợt. Quá nhiều người đã quên mất kỹ thuật cổ xưa và hiệu quả này.
datagod

Cách hiệu quả nhất để thay đổi cột mới được thêm vào thành KHÔNG NULL (sau khi nó đã được cập nhật với các giá trị và không có giá trị null nào trong cột)? Bảng của tôi có khoảng 50 triệu hồ sơ. Máy chủ SQL thực tế đang làm gì? Có phải nó xác nhận các giá trị và cột đánh dấu là không null?
rrejc
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.