主な目的:テーブルにパーティションを追加して、古い注文の削除をノンブロッキング/キッカーにする(また、パーティションを理解する)
次のような既存のテーブルOrderがあります。
CREATE TABLE Order (
OrderId INT,
OrderDate Datetime,
Quantity INT,
CONSTRAINT [PK_OrderId] PRIMARY KEY CLUSTERED
(
[OrderId] ASC
)
ON [PRIMARY];
このテーブルには、過去10年間の5,000万行が含まれています。過去5年間のデータのみが必要です。
私はこのようなパーティション関数を持っています:
CREATE PARTITION FUNCTION OrderPF (datetime)
AS RANGE RIGHT FOR VALUES ('2014-01-01')
私はこのようなパーティションスキームを持っています:
CREATE PARTITION SCHEME OrderPS
AS PARTITION OrderPF ALL TO ([PRIMARY])
私の質問はどのように進めるかです。テーブルの主キーがまだ必要です。
[OrderDate]列はクラスター化インデックスの一部である必要がありますか?(メインの質問)
CREATE UNIQUE CLUSTERED INDEX IX_Order ON Order(OrderDate,OrderId) ON OrderPS(OrderDate) ;
もしそうなら、純粋に[OrderId]に追加の非クラスター化主キーを作成する必要がありますか?
ALTER TABLE Order ADD CONSTRAINT PK_OrderId PRIMARY KEY NONCLUSTERED (Id) ON [PRIMARY];
これは正しいアプローチですか?
OrderId
が単調増加している場合は、その上で分割できます。次に、保持する必要のあるデータがない古いパーティションを切り捨てることができます。何かのようなもの:
create partition function pf_OrderId(int)
as range right for values (0,1000000,2000000,3000000,4000000,5000000,6000000,7000000,8000000,9000000)
create partition scheme ps_OrderId
as partition pf_OrderId all to ([Primary])
go
CREATE TABLE [Order] (
OrderId INT,
OrderDate Datetime,
Quantity INT,
constraint [PK_OrderId] primary key clustered (OrderId)
)
ON ps_OrderId(OrderId)
go
--then you can examine the max OrderDate in each partition when trimming old data
select p.partition_number,
(select max(OrderDate) MaxOrderDate
from [Order]
where $PARTITION.pf_OrderId(OrderId) = p.partition_number) MaxOrderDate
from sys.partitions p
where p.object_id = object_id('Order')
and p.index_id = 1
そしてもちろん、パーティションの粒度を調整して、データ保持要件にほぼ合わせることもできます。また、古いデータをパージする必要がある場合は、N個のパーティションを切り捨て、最大で1つのパーティションでDELETEを実行します。また、いつでもパーティション関数を分割して、年または四半期の初めの一夜など、重要なときにパーティション境界を挿入できます。
既存のテーブルをパーティション構成に移動するには、すべてのインデックスとクラスター化された主キー制約を削除し、新しいパーティション構成に再作成します。パーティション構成でクラスター化インデックスを作成すると、その後作成されるインデックスはデフォルトでそこに配置されます。最初に非クラスター化インデックスを削除しない場合、クラスター化されたPKを削除するとインデックスが再構築され、再作成すると再構築されますが、パーティション化されません。例えば
CREATE TABLE [Order] (
OrderId INT,
OrderDate Datetime,
Quantity INT,
constraint [PK_OrderId] primary key clustered (OrderId),
index ix_Order_Orderdate (OrderDate)
)
go
create partition function pf_OrderId(int)
as range right for values (0,1000000,2000000,3000000,4000000,5000000,6000000,7000000,8000000,9000000)
create partition scheme ps_OrderId
as partition pf_OrderId all to ([Primary])
go
drop index ix_Order_Orderdate on [Order]
alter table [Order]
drop constraint [PK_OrderId]
alter table [Order]
add constraint [PK_OrderId] primary key clustered (OrderId)
on ps_OrderId(OrderId)
create index ix_Order_Orderdate on [Order](OrderDate)
次に、クラスター化インデックスと非クラスター化インデックスの両方がパーティション分割されていることを確認します。
select i.name index_name, p.partition_number
from sys.partitions p
join sys.indexes i
on p.object_id = i.object_id
and p.index_id = i.index_id
where p.object_id = object_id('Order')
パーティション分割シナリオに関連するすべての一意の制約(主キーを含む)[〜#〜] [〜#〜]には、パーティション列が定義されている必要がありますベースインデックス定義の一部として(インデックスキーのサブセット) 単に含まれている列ではありません)。この例では、orderdate
はベースインデックス定義の一部ではないため、非クラスター化主キーをパーティション分割することはできません。
あなたがあなたの目標を達成するとは思わない
テーブルにパーティションを追加して、古い注文の削除をノンブロッキング/キッカーにする
主キーが、パーティション化するクラスター化インデックスと同じパーティション構成/機能に参加できないという単純な事実により、パーティション分割を使用する。 ID
によって独自のパーティションスキーム/関数で主キーをパーティション分割した場合でも、これらの2つのインデックスは整列されないため、パーティション切り替えを使用して、最小限のログでデータを効率的に削除できます。
私の意見では、クラスター化されていない主キーとincludeorderdate
列を作成できます。これにより、削除する行をエンジンがより速く検索できるようになりますが、 dはおそらく---(batch削除をchunksで実行して、関連するロックの量を制限する必要があります。
パーティショニングがあなたの問題の答えだとは思いません。