Wednesday, October 03, 2018

Partition Bảng Đã Có Sẵn


Bài viết tham khảo tại:http://www.sqlviet.com/blog/partition-bang-da-co-san

Partition Bảng Đã Có Sẵn

Vũ Huy Tâm

Trong loạt bài về phân đoạn bảng và index, tôi đã giới thiệu về kiến trúc phân đoạn của SQL Server. Các ví dụ nêu trong các bài đó đều sử dụng bảng được tạo lần đầu và áp dụng phân đoạn lên nó. Một câu hỏi thường gặp là, làm thế nào để phân đoạn một bảng đã có sẵn dữ liệu? Bảng này có thể chưa được phân đoạn, hoặc đã được phân đoạn theo một cách khác, nay bạn muốn phân đoạn lại theo cách hợp lý hơn.
Có một cách làm thực ra rất đơn giản mà nếu bạn để ý một tẹo là thấy ngay, đó là trong SQL Server clustered index chính là bảng, nói cách khác là bảng được lưu trữ thành một cây index và cây này chính là clustered index. Vì vậy để phân đoạn bảng bạn chỉ việc phân đoạn clustered index của nó, bằng cách tạo lại clustered index trên partition scheme.
Trong trường hợp phổ biến, clustered index thường đi liền với primary key. Ở ví dụ dưới, giả sử bạn đã có bảng BanHang với primary key và clustered index trên trường ID, bảng này không được phân đoạn.
CREATE TABLE dbo.BanHang(ID INT IDENTITY NOT NULL, 
NgayGD DATETIME NOT NULL, 
MaSP INT NOT NULL,
SoLuong INT NOT NULL, 
Gia INT NOT NULL,
CONSTRAINT PK_BanHang PRIMARY KEY CLUSTERED (ID)
)
Nay bạn muốn phân đoạn bảng, có hai khả năng xảy ra:
(1) bạn phân đoạn bảng trên trường ID, nghĩa là vẫn giữ nguyên định nghĩa của primary key và clustered index (giữ nguyên trường cũ) chỉ muốn phân đoạn nó ra, dựa vào partition scheme PScheme_ID. Bạn chỉ việc tạo lại index như sau:
CREATE UNIQUE CLUSTERED INDEX PK_BanHang ON dbo.BanHang(ID) 
WITH (DROP_EXISTING = ON)
ON PScheme_ID(ID)
Điểm chính của đoạn lệnh trên là mệnh đề “WITH (DROP_EXISTING = ON)”, nó sẽ tự động xây dựng lại index thay vì bạn phải xóa đi rồi tạo lại.
(2) Bạn muốn phân đoạn bảng trên một trường khác, ví dụ NgayGD. Vì trường partition key cần phải có mặt trong clustered index, bạn cần tạo lại clustered index (và primary key) trong đó phải chứa thêm trường NgayGD. Vì định nghĩa của primary key và clustered index khác so với trước, bạn không thể dùng WITH (DROP_EXISTING = ON) được nữa. Nếu cố tình chạy đoạn lệnh này:
CREATE UNIQUE CLUSTERED INDEX PK_BanHang ON dbo.BanHang(ID,NgayGD) 
WITH (DROP_EXISTING = ON)
ON PScheme_NGD(NgayGD)
Bạn sẽ gặp lỗi:
Cannot recreate index ‘PK_BanHang’. The new index definition does not match the constraint being enforced by the existing index.
Thay vào đó, bạn cần xóa đi và tạo lại:
ALTER TABLE BanHang DROP CONSTRAINT PK_BanHang
GO
CREATE UNIQUE CLUSTERED INDEX PK_BanHang ON dbo.BanHang(ID,NgayGD) 
ON PScheme_NGD(NgayGD)
--hoặc
ALTER TABLE dbo.BanHang ADD CONSTRAINT PK_BanHang PRIMARY KEY CLUSTERED (ID,NgayGD) ON PScheme_NGD(NgayGD)
Lý do tại sao cần 2 trường ID và NgayGD trong index là vì ID cần thiết để duy trì tính duy nhất, và NgayGD cần có mặt để làm partition key.
Trong trường hợp ít phổ biến hơn, clustered index không đi kèm với primary key, hay nói tổng quát là nó đứng một mình không gắn với một constraint nào. Khi đó bạn có thể tạo lại clustered index với bổ sung thêm trường mới mà vẫn dùng được mệnh đề “WITH (DROP_EXISTING = ON)”:
CREATE TABLE dbo.BanHang(ID INT IDENTITY NOT NULL, 
NgayGD DATETIME NOT NULL, 
MaSP INT NOT NULL,
SoLuong INT NOT NULL, 
Gia INT NOT NULL
)
CREATE UNIQUE CLUSTERED INDEX CI_BanHang ON dbo.BanHang(ID) 
GO
CREATE UNIQUE CLUSTERED INDEX CI_BanHang ON dbo.BanHang(ID,NgayGD) 
WITH (DROP_EXISTING = ON)
ON PScheme_NGD(NgayGD)

No comments: