現在、1つのテーブルで約70億行に達しており、データベース全体の最大ディスク容量に近づいています。
1つの大きなテーブルの新しいデータを新しいディスクに保存する必要があります。
datetime
によるパーティション分割を確認しましたが、これは明らかな選択のようです。これは、6か月で新しいサーバーを取得する前の暫定的なソリューションですが、「今」のソリューションが必要です。
どうすればこれを達成できますか?すべての新しいデータが新しいディスクに移動するように手動パーティションを実装できますか?
私が見たものはすべて、毎月のオプションのようなものを作成する必要がありますが、新しいものをすべて新しいディスクに置きたいだけです。
1つのオプションは、既存のデータを月ごとに分割し、手動でパーティションを移動することです。
これが可能かどうかさえわからないので、上記を達成するための最良の解決策についてのフィードバックをいただければ幸いです。
SQL Server 2017 Enterprise Edition。
ここでの通常の短期的な解決策は、単純に 一部のインデックスとテーブルを新しいファイルグループに移動 して、プライマリファイルグループのスペースを解放することです。
だが
すべての新しいデータが新しいディスクに移動するように手動パーティションを実装できますか?
はい、できます。重要なアイデアは、既存のテーブルと互換性のあるパーティション構成に新しいテーブルを作成し、クラスター化インデックスキー列でパーティション分割することです。次に、テーブルをそのパーティション構成のパーティションに切り替え、そのパーティション関数を分割して、新しい行が新しいファイルグループに移動するようにします。
そして、「原始」パーティションのみでパーティション化されたテーブルを作成し、非パーティション化テーブルにCHECK制約を必要とせずに非パーティション化テーブルを原始的パーティションに切り替えることができることを発見しました。
これがエンドツーエンドのデモです。
use master
go
drop database parttest
go
create database parttest
go
use parttest
go
drop table if exists large
go
create table large(id int identity primary key, a char(1000), b int, c datetime);
create index ix_large_b on large(b);
--load some data
with q as
(
select top 100000 row_number() over (order by (select null)) n
from sys.messages m, sys.objects o
)
insert into large(a,b,c)
select replicate('z',n%989), n%39, getdate()-n%1000
from q;
--add a new filegroup with a single file
alter database current
add filegroup newfg
alter database current
add file (name = 'newfg_data', filename = 'c:\temp\newfg_data.mdf')
to filegroup newfg
--create the new partition function and partition scheme
--but don't specify any boundary points, so the target
--table can be switched in without a check constraint
create partition function pf_large(int)
as range right for values ()
create partition scheme ps_large
as partition pf_large all to ([Primary])
--create the table to switch into
create table large2(id int identity primary key, a char(1000), b int, c datetime)
on ps_large(id);
--create the secondary indexes on the new table
--if you don't create them they won't be switched
create index ix_large2_b on large2(b) ;
alter table large switch to large2 partition 1
-- drop and rename
begin transaction
drop table large
exec sp_rename 'large2','large'
commit
--reset the identity values
dbcc checkident('large')
go
--split the partition function so new rows to to the new filegroup
alter partition scheme ps_large next used newfg
begin transaction
declare @splitPoint int = 1+(select max(id) from large with (tablockx) )
alter partition function pf_large() split range (@splitPoint)
commit
go
--load some more data
with q as
(
select top 100000 row_number() over (order by (select null)) n
from sys.messages m, sys.objects o
)
insert into large(a,b,c)
select replicate('z',n%989), n%39, getdate()-n%1000
from q;
go
--check that it went to the new filegroup
select i.index_id, p.partition_number, ds.name fg, au.data_pages
from sys.tables t
join sys.indexes i
on t.object_id =i.object_id
left join sys.partitions p
on p.object_id = t.object_id
and p.index_id = i.index_id
left join sys.allocation_units au
on (au.type in (1,3) and au.container_id = p.hobt_id)
or(au.type = 2 and au.container_id = p.partition_id)
left join sys.data_spaces ds
on ds.data_space_id = au.data_space_id
where t.object_id = object_id('large')
order by ds.data_space_id, index_id, partition_number
出力
index_id partition_number fg data_pages
----------- ---------------- ------------ --------------------
1 1 PRIMARY 14286
2 1 PRIMARY 174
1 2 newfg 14286
2 2 newfg 231
このテーブルを参照する外部キー制約を削除して再作成する必要があります。また、切り替え後にFK制約を再作成すると、スイッチはDDL中にテーブルスキャンを必要とするため、オフライン操作に時間がかかる場合があります。稼働時間を最適化するには、NOCHECKを使用してFK制約を再作成し、後でチェックします。それまではDMLに適用されますが、クエリオプティマイザーによって信頼されません。
テーブルにクラスタ化インデックスだけではない場合は、次のことができます。
これを行う方法の詳細については、 here を参照してください。
非クラスター化インデックスを別のファイルグループ/ディスクに移動してデータファイル内のスペースを解放したら、データファイルを圧縮できます(DBCC圧縮データベース)
この後、ドライブに空きスペースができてから、インデックスの再構築を検討してください。これにより、断片化が解消され、圧縮なしでも副作用としてスペース消費を大幅に削減できます。
そして最後に、インデックスを再構築しながら、data_compression = page
最大のテーブルのすべてのインデックスに追加して、さらに多くのスペースを節約します(新しいデータを圧縮/解凍するためのCPUオーバーヘッドがそれ以上問題にならない場合)。
このように、パーティション化は本当に必要ありません