Đầu tiên trước khi tôi cung cấp giải pháp, tôi muốn xác nhận giả định của bạn:
Theo như tôi có thể thấy có một sự phụ thuộc ràng buộc lược đồ của lược đồ phân vùng (và hàm) vào bảng ngăn chặn sửa đổi kiểu dữ liệu.
Bạn nói đúng; thực tế là bạn có một hàm phân vùng được xác định cho kiểu dữ liệu INT
đang ngăn bạn thay đổi kiểu dữ liệu của cột của bạn ... Đáng buồn thay, bạn bị mắc kẹt với bảng hiện tại vì theo cách hiểu của tôi, không thể điều chỉnh kiểu dữ liệu của hàm phân vùng mà không bỏ / tạo lại nó .... điều mà bạn không thể làm được vì bạn có các bảng phụ thuộc vào nó. Vì vậy, về cơ bản đây là kịch bản gà và trứng .
Tôi không thấy một giải pháp để cập nhật loại cột trên cơ sở dữ liệu này, chứ chưa nói đến cơ sở dữ liệu sản xuất. Chúng tôi có thể đủ khả năng một số thời gian ngừng bảo trì, giả sử + - 60 phút, nhưng không còn nữa. Những lựa chọn của tôi là gì?
Một giải pháp khả thi cho vấn đề của bạn là tận dụng Chế độ xem được phân vùng . Chức năng này đã tồn tại mãi mãi và thường bị bỏ qua, nhưng Chế độ xem được phân vùng sẽ cung cấp cho bạn một cách để vượt qua INT
giới hạn dữ liệu của bạn bằng cách thêm dữ liệu mới vào một bảng khác trong đó ID
cột là BIGINT
kiểu dữ liệu. Bảng mới này cũng cần có chức năng / lược đồ phân vùng tốt hơn bên dưới nó và hy vọng sẽ được duy trì tốt hơn một chút trong tương lai. Bất kỳ truy vấn nào đang trỏ đến bảng cũ sau đó sẽ được trỏ đến Chế độ xem được phân vùng và bạn sẽ không gặp phải vấn đề giới hạn dữ liệu.
Hãy để tôi giải thích với một ví dụ. Sau đây là một trò giải trí tầm thường của bảng được phân vùng hiện tại của bạn, bao gồm một phân vùng, như sau:
-- Create your very frustraiting parition scheme
CREATE PARTITION FUNCTION dear_god_why_this_logic (INT)
AS RANGE RIGHT FOR VALUES (0);
-- Scheme to store data on PartitionedData Filegroup
CREATE PARTITION SCHEME dear_god_why_this_scheme
AS PARTITION dear_god_why_this_logic ALL TO ([PRIMARY]);
-- Create Partitioned Table
CREATE TABLE dbo.TestPartitioned
(
ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
VAL CHAR(1)
) ON dear_god_why_this_scheme (ID);
--Populate Table with Data
INSERT INTO dbo.TestPartitioned WITH (TABLOCK) (VAL)
SELECT CHAR(ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) % 128)
FROM master.sys.configurations t1
CROSS JOIN master.sys.configurations t2
CROSS JOIN master.sys.configurations t3;
Hãy nói vì lý do rằng tôi đang tiến gần đến INT
giới hạn (mặc dù rõ ràng là tôi không). Vì tôi không muốn hết các giá INT
trị hợp lệ trong ID
cột, nên tôi sẽ tạo một bảng tương tự, nhưng sử dụng BIGINT
cho ID
cột thay thế. Bảng này sẽ được định nghĩa như sau:
CREATE PARTITION FUNCTION lets_maintain_this_going_forward (BIGINT)
AS RANGE RIGHT FOR VALUES (0, 500000, 1000000, 1500000, 2000000);
-- Scheme to store data on PartitionedData Filegroup
CREATE PARTITION SCHEME lets_maintain_this_going_forward_scheme
AS PARTITION lets_maintain_this_going_forward ALL TO ([PartitionedData]);
-- Table for New Data going forward with new ID datatype of BIGINT
CREATE TABLE dbo.TestPartitioned_BIGINT
(
ID BIGINT IDENTITY(500000,1) PRIMARY KEY CLUSTERED,
VAL CHAR(1)
) ON lets_maintain_this_going_forward_scheme (ID);
-- Add check constraint to be used by Partitioned View
ALTER TABLE dbo.TestPartitioned_BIGINT ADD CONSTRAINT CK_ID_BIGINT CHECK (ID > CAST(499999 AS BIGINT));
Một vài lưu ý ở đây:
Phân vùng bảng trên bảng mới
Bảng mới này cũng sẽ được phân vùng dựa trên yêu cầu của bạn. Nên nghĩ về nhu cầu bảo trì trong tương lai, vì vậy hãy tạo một số nhóm tệp mới, xác định chiến lược căn chỉnh phân vùng tốt hơn, v.v. Ví dụ của tôi là giữ cho nó đơn giản, vì vậy tôi sẽ ném tất cả các phân vùng của mình vào một Filegroup. Đừng làm điều đó trong sản xuất, thay vào đó hãy làm theo Thực tiễn tốt nhất về phân vùng bảng , với sự cho phép của Brent Ozar et. al.
Kiểm tra ràng buộc
Vì tôi muốn tận dụng Chế độ xem được phân vùng, tôi cần thêm một CHECK CONSTRAINT
vào bảng mới này. Tôi biết rằng câu lệnh chèn của tôi đã tạo ra ~ 440k hồ sơ, vì vậy để an toàn, tôi sẽ bắt đầu IDENTITY
hạt giống của mình ở mức 500k và tạo ra một CONSTRAINT
định nghĩa này. Ràng buộc sẽ được sử dụng bởi trình tối ưu hóa khi đánh giá bảng nào có thể được loại bỏ khi Chế độ xem phân vùng cuối cùng được gọi.
Bây giờ để trộn hai bàn với nhau
Các khung nhìn được phân vùng không đặc biệt làm tốt khi bạn ném các kiểu dữ liệu hỗn hợp vào chúng khi nói đến cột phân vùng trong các bảng bên dưới. Để giải quyết vấn đề này, chúng tôi phải duy trì ID
cột hiện tại trong bảng hiện tại của bạn làm BIGINT
giá trị. Chúng tôi sẽ làm điều đó bằng cách thêm Cột được tính toán liên tục , như sau:
-- Append Calculated Columns of New Datatype to Old Table
-- WARNING: This will take a while against a large data set and will likely lock the table
ALTER TABLE dbo.TestPartitioned ADD ID_BIG AS (CAST(ID AS BIGINT)) PERSISTED
GO
-- Add Constraints on Calculated Column
-- WARNING: This will likely lock the table
ALTER TABLE dbo.TestPartitioned ADD CONSTRAINT CK_ID_TestPartitioned_BIGINT CHECK(ID_BIG <= CAST(499999 AS BIGINT));
GO
-- Create a new Nonclustered index on ID_BIG to act as new "pkey"
CREATE NONCLUSTERED INDEX IX_TestPartitioned__BIG_ID__VAL ON dbo.TestPartitioned (ID_BIG) INCLUDE (VAL);
Tôi cũng đã thêm một CHECK CONSTRAINT
bảng khác trên bảng cũ (để hỗ trợ Loại bỏ phân vùng khỏi Chế độ xem được phân vùng cuối cùng của chúng tôi) và Chỉ mục không phân cụm mới sẽ hoạt động như một chỉ mục khóa chính (bởi vì các tra cứu bắt nguồn từ Chế độ xem được phân vùng sẽ diễn ra được xảy ra chống lại ID_BIG
thay vì ID
).
Với Cột được tính toán mới và Kiểm tra ràng buộc tại chỗ, cuối cùng tôi cũng có thể xác định Chế độ xem được phân vùng, như sau:
-- Build a Partitioned View on Top of the old and new tables
CREATE VIEW dbo.vw_TableAll
WITH SCHEMABINDING
AS
SELECT ID_BIG AS ID, VAL FROM dbo.TestPartitioned
UNION ALL
SELECT ID, VAL FROM dbo.TestPartitioned_BIGINT
GO
Chạy một truy vấn nhanh đối với chế độ xem này sẽ xác nhận chúng tôi có hoạt động loại bỏ phân vùng (vì bạn không thấy bất kỳ tra cứu nào xảy ra đối với bảng mới mà chúng tôi đã tạo):
SELECT *
FROM dbo.vw_TableAll
WHERE ID < CAST(500 AS BIGINT);
Kế hoạch thực hiện:
Ở giai đoạn này, bạn sẽ cần thực hiện một vài thay đổi cho ứng dụng của mình:
- Dừng chèn các bản ghi mới vào bảng cũ, và thay vào đó chèn chúng vào bảng mới. Chúng tôi không được phép chèn các bản ghi vào Chế độ xem được phân vùng vì chúng tôi đang sử dụng
IDENTITY
các giá trị trong các bảng bên dưới. Chế độ xem được phân vùng không cho phép điều này , vì vậy bạn phải chèn các bản ghi trực tiếp vào bảng mới trong kịch bản này.
- Điều chỉnh bất kỳ
SELECT
truy vấn nào (trỏ đến bảng cũ) để trỏ đến Chế độ xem được phân vùng. Ngoài ra, bạn có thể đổi tên bảng cũ (ví dụ TableName_Old) và tạo dạng xem dưới dạng tên của các bảng cũ (ví dụ: Tên bảng); bạn muốn đến đây như thế nào là tùy thuộc vào bạn.
Bản ghi mới vào bảng mới
Tại thời điểm này, các bản ghi mới sẽ được chèn vào bảng mới. Tôi sẽ mô phỏng điều này bằng cách chạy như sau:
--Populate Table with Data
INSERT INTO dbo.TestPartitioned_BIGINT WITH (TABLOCK) (VAL)
SELECT CHAR(ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) % 128)
FROM master.sys.configurations t1
CROSS JOIN master.sys.configurations t2
CROSS JOIN master.sys.configurations t3;
GO
Một lần nữa, Hạt giống danh tính của tôi được định cấu hình để tôi sẽ không có bất kỳ xung đột ID nào giữa hai bảng. Trên CHECK CONSTRAINTS
cả hai bảng cũng nên thực thi điều này. Hãy xác nhận rằng Loại bỏ phân vùng vẫn đang xảy ra:
SELECT *
FROM dbo.vw_TableAll
WHERE ID > CAST(300000 AS BIGINT)
AND ID < CAST(300500 AS BIGINT);
SELECT *
FROM dbo.vw_TableAll
WHERE ID > CAST(500000 AS BIGINT)
AND ID < CAST(500500 AS BIGINT);
Kế hoạch thực hiện:
Hãy lưu ý rằng hầu hết các truy vấn sẽ có khả năng kéo dài cả hai bảng. Mặc dù chúng tôi sẽ không thể tận dụng việc loại bỏ phân vùng trong các tình huống này, các kế hoạch truy vấn sẽ vẫn tối ưu nhất có thể với lợi ích mà bạn không phải viết lại các truy vấn cơ bản của mình (nếu bạn quyết định đặt tên cho chế độ xem giống nhau như bảng cũ của bạn).
Làm gì bây giờ?
Vâng, điều này hoàn toàn phụ thuộc vào bạn. Nếu các bản ghi hiện tại sẽ không bao giờ biến mất và bạn hài lòng với hiệu suất từ Chế độ xem được phân vùng, hãy rót bia kỷ niệm vì bạn đã hoàn thành. Huzzah!
Nếu bạn muốn hợp nhất bảng cũ vào bảng mới, bạn sẽ phải chọn các cửa sổ bảo trì để thực hiện chuỗi thao tác tiếp theo. Về cơ bản, bạn sẽ bỏ các ràng buộc trên các bảng (sẽ phá vỡ thành phần loại bỏ phân vùng của Chế độ xem được phân vùng), sao chép các bản ghi gần đây nhất của bạn từ bảng cũ sang bảng mới, xóa các bản ghi này khỏi bảng cũ, và sau đó cập nhật các ràng buộc (để Chế độ xem được phân vùng có thể tận dụng loại bỏ phân vùng một lần nữa). Do khối lượng dữ liệu bạn có trong các bảng hiện có, bạn có thể phải trải qua một vài vòng của quy trình này để hợp nhất mọi thứ. Các bước được tóm tắt như sau:
-- During a maintenance window, transfer old records to new table if you so choose
-- Drop Check Constraint while transferring over records
ALTER TABLE dbo.TestPartitioned_BIGINT DROP CONSTRAINT CK_ID_BIGINT;
-- Retain Identity Values
SET IDENTITY_INSERT dbo.TestPartitioned_BIGINT ON
-- Copy records into the new table
INSERT INTO dbo.TestPartitioned_BIGINT (ID, VAL)
SELECT ID_BIG, VAL
FROM dbo.TestPartitioned
WHERE ID > 300000
SET IDENTITY_INSERT dbo.TestPartitioned_BIGINT OFF
-- Enable Check Constraint after transferred records are complete, ensuring the Check Constraint is defined on the proper ID value
ALTER TABLE dbo.TestPartitioned_BIGINT ADD CONSTRAINT CK_ID_BIGINT CHECK (ID > CAST(300000 AS BIGINT));
GO
-- Purge records from original table
DELETE
FROM dbo.TestPartitioned
WHERE ID > 300000
-- Recreate Check Constraint on original table, ensuring the Check Constraint is defined on the proper ID value
ALTER TABLE dbo.TestPartitioned DROP CONSTRAINT CK_ID_TestPartitioned_BIGINT;
GO
ALTER TABLE dbo.TestPartitioned ADD CONSTRAINT CK_ID_TestPartitioned_BIGINT CHECK(ID_BIG <= CAST(300000 AS BIGINT));
GO
Nếu có thể, hãy kiểm tra điều này trong một môi trường không sản xuất. Tôi không bỏ qua thử nghiệm trong sản xuất. Hy vọng câu trả lời này có ích, và nếu bạn có bất kỳ câu hỏi nào, vui lòng gửi bình luận và tôi sẽ cố gắng hết sức để nhanh chóng quay lại với bạn.