web-dev-qa-db-ja.com

ディスク容量が不足しています。新しいデータを別のディスクに保存してください

現在、1つのテーブルで約70億行に達しており、データベース全体の最大ディスク容量に近づいています。

1つの大きなテーブルの新しいデータを新しいディスクに保存する必要があります。

datetimeによるパーティション分割を確認しましたが、これは明らかな選択のようです。これは、6か月で新しいサーバーを取得する前の暫定的なソリューションですが、「今」のソリューションが必要です。

どうすればこれを達成できますか?すべての新しいデータが新しいディスクに移動するように手動パーティションを実装できますか?

私が見たものはすべて、毎月のオプションのようなものを作成する必要がありますが、新しいものをすべて新しいディスクに置きたいだけです。

1つのオプションは、既存のデータを月ごとに分割し、手動でパーティションを移動することです。

これが可能かどうかさえわからないので、上記を達成するための最良の解決策についてのフィードバックをいただければ幸いです。

SQL Server 2017 Enterprise Edition。

4
Quade

ここでの通常の短期的な解決策は、単純に 一部のインデックスとテーブルを新しいファイルグループに移動 して、プライマリファイルグループのスペースを解放することです。

だが

すべての新しいデータが新しいディスクに移動するように手動パーティションを実装できますか?

はい、できます。重要なアイデアは、既存のテーブルと互換性のあるパーティション構成に新しいテーブルを作成し、クラスター化インデックスキー列でパーティション分割することです。次に、テーブルをそのパーティション構成のパーティションに切り替え、そのパーティション関数を分割して、新しい行が新しいファイルグループに移動するようにします。

そして、「原始」パーティションのみでパーティション化されたテーブルを作成し、非パーティション化テーブルに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に適用されますが、クエリオプティマイザーによって信頼されません。

テーブルにクラスタ化インデックスだけではない場合は、次のことができます。

  1. データベースの新しいファイルグループを作成する
  2. 新しいファイルグループに新しいファイルを追加し、新しいファイルの場所を指定します-新しいディスク
  3. 非クラスター化インデックスをこの新しいファイルグループ/ディスクに移動する

これを行う方法の詳細については、 here を参照してください。

非クラスター化インデックスを別のファイルグループ/ディスクに移動してデータファイル内のスペースを解放したら、データファイルを圧縮できます(DBCC圧縮データベース)

この後、ドライブに空きスペースができてから、インデックスの再構築を検討してください。これにより、断片化が解消され、圧縮なしでも副作用としてスペース消費を大幅に削減できます。

そして最後に、インデックスを再構築しながら、data_compression = page最大のテーブルのすべてのインデックスに追加して、さらに多くのスペースを節約します(新しいデータを圧縮/解凍するためのCPUオーバーヘッドがそれ以上問題にならない場合)。

このように、パーティション化は本当に必要ありません

3
Aleksey Vitsko