磁盘空间不足,开始将新数据保存到不同的磁盘

Qua*_*ade 4 sql-server disk-space sql-server-2017

我目前在一张表上大约有 70 亿行,并且接近整个数据库的最大磁盘空间。

我需要开始将一个大表上的新数据保存到新磁盘。

我已经看过分区datetime,这似乎是显而易见的选择 这是我们在 6 个月内获得新服务器之前的临时解决方案,但需要“现在”解决方案。

我将如何实现这一目标?我可以实施手动分区以便所有新数据都转到新磁盘吗?

我所看到的一切都需要创建类似于每月选项的内容,而我只想将所有新内容放在新磁盘上。

一种选择是按月拆分现有数据,然后手动移动分区。

我什至不确定这是否可行,因此希望获得有关实现上述目标的最佳解决方案的一些反馈。

SQL Server 2017 企业版。

Dav*_*oft 6

这里正常的短期解决方案是简单地将一些索引和表移动到新的文件组以释放主文件组中的空间。

我可以实施手动分区以便所有新数据都转到新磁盘吗?

是的你可以。关键思想是在与现有表兼容的分区方案上创建一个新表,并在聚集索引键列上进行分区。然后将表切换到该分区方案上的分区,并拆分其分区功能,以便新行进入新文件组。

我刚刚发现你可以创建一个只有“原始”分区的分区表,然后将一个非分区表切换到原始分区,而不需要对非分区表设置 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 
Run Code Online (Sandbox Code Playgroud)

产出

index_id    partition_number fg           data_pages
----------- ---------------- ------------ --------------------
1           1                PRIMARY      14286
2           1                PRIMARY      174
1           2                newfg        14286
2           2                newfg        231
Run Code Online (Sandbox Code Playgroud)

您将不得不删除并重新创建引用此表的外键约束。并且在切换之后重新创建 FK 约束,切换需要在 DDL 期间进行表扫描,因此可能是冗长的离线操作。要优化正常运行时间,您可以使用 NOCHECK 重新创建 FK 约束,然后稍后再检查它们。在此之前,它们将针对 DML 强制执行,但不受查询优化器的信任。