我有SQL Server 2008 Ent
两张OLTP database
大桌子。如何在filegroup
不中断服务的情况下将这些表移动到另一个表?现在,这些表中每秒插入大约 100-130 条记录和更新 30-50 条记录。每张表大约有100M条记录和6个field
s(包括一个字段geography
)。
我正在 Google 中寻找解决方案,但所有解决方案都包含
创建第二个表,从第一个表插入行,删除第一个表等
我可以使用分区函数来解决这个问题吗?
我有SQL Server 2008 Ent
两张OLTP database
大桌子。如何在filegroup
不中断服务的情况下将这些表移动到另一个表?现在,这些表中每秒插入大约 100-130 条记录和更新 30-50 条记录。每张表大约有100M条记录和6个field
s(包括一个字段geography
)。
我正在 Google 中寻找解决方案,但所有解决方案都包含
创建第二个表,从第一个表插入行,删除第一个表等
我可以使用分区函数来解决这个问题吗?
如果只想将表移动到新文件组,则需要在所需的新文件组上重新创建表上的聚集索引(毕竟:聚集索引是表数据)。
你可以这样做,例如:
CREATE CLUSTERED INDEX CIX_YourTable
ON dbo.YourTable(YourClusteringKeyFields)
WITH DROP_EXISTING
ON [filegroup_name]
或者如果您的聚集索引是唯一的:
CREATE UNIQUE CLUSTERED INDEX CIX_YourTable
ON dbo.YourTable(YourClusteringKeyFields)
WITH DROP_EXISTING
ON [filegroup_name]
这将创建一个新的聚集索引并删除现有的,并在您指定的文件组中创建新的聚集索引 - 瞧,您的表数据已被移动到新的文件组。
有关您可能要指定的所有可用选项的详细信息,请参阅CREATE INDEX 上的 MSDN 文档。
这当然还没有处理分区,但这完全是另一回事......
要回答这个问题,首先我们要明白
第一步是找出有关我们要移动的表的更多信息。我们通过执行这个 T-SQL 来做到这一点:
sp_help N'<<your table name>>'
输出将显示标题为“Data_located_on_filegroup”的列。这是了解您的表数据在哪个文件组上的便捷方式。但更重要的是显示有关表索引的信息的输出。(如果您只想查看有关表索引的信息,只需运行sp_helpindex N'<<your table name>>'
)您的表可能有 1)没有索引(所以它是一个堆),2)单个索引,或 3)多个索引。如果 index_description 以 'clustered, unique, ...' 开头,那就是您要移动的索引。如果索引也是主键,那没关系,你仍然可以移动它。
要移动索引,请记下上述帮助查询结果中显示的 index_name 和 index_keys,然后使用它们填写<<blanks>>
以下查询:
CREATE UNIQUE CLUSTERED INDEX [<<name of clustered index>>]
ON [<<table name>>]([<<column name the index is on - from index_keys above>>])
WITH (DROP_EXISTING = ON, ONLINE = ON)
ON <<name of file group you want to move the index to>>
上面的DROP EXISTING, ONLINE
选项很重要。 DROP EXISTING
确保索引不重复,并ONLINE
在移动时保持表在线(现在仅在企业版中可用)。
如果您要移动的索引不是聚集索引,则将UNIQUE CLUSTERED
上面替换为NONCLUSTERED
要移动堆表,请向其中添加聚集索引,然后运行上述语句将其移动到不同的文件组,然后删除索引。
现在,返回并sp_help
在您的表上运行,并检查结果以查看您的表和索引数据现在所在的位置。
如果您的表有多个索引,那么在您运行上述语句移动聚集索引后,sp_helpindex
将显示您的聚集索引在新文件组上,但任何剩余索引仍将在原始文件组上。该表将继续正常运行,但您应该有充分的理由希望索引位于不同的文件组中。如果您希望表及其所有索引位于同一文件组中,请对每个索引重复上述说明,CREATE [NONCLUSTERED, or other] ... DROP EXISTING...
并根据需要进行替换,具体取决于您要移动的索引类型。
分区是一种解决方案,但您可以使用以下方法将聚集索引“移动”到新文件组而不会中断服务(在某些情况下,请参见下面的链接)
CREATE CLUSTERED /*oops*/ INDEX ... WITH (DROP_EXISTING = ON, ONLINE = ON, ...) ON newfilegroup
聚集索引是数据,这与移动文件组相同。
请参阅创建索引
这取决于您的主键是否是集群的,这会改变我们的操作方式
SQL Server 联机丛书的这段摘录说明了一切:“因为聚集索引的叶级别和数据页在定义上是相同的,所以创建聚集索引并使用 ON partition_scheme_name 或 ON filegroup_name子句有效地从文件组中移动表表在其上创建到新的分区方案或文件组。" (来源 - http://msdn.microsoft.com/en-us/library/ms188783.aspx)来自(http://www.mssqltips.com/sqlservertip/2442/move-data-between-sql-server-database -文件组/)
正如其他朋友所说的那样,marc_s 接受的答案如下是屏幕截图为您提供了另一种使用 SSMS GUI 的方法。
请注意,您可以轻松移动到存储选项卡中索引属性的另一个文件组
请注意,重新创建聚集索引只会移动“原始”列等int, bit, datetime
。
要移动varchar(max), varbinary
和其他“blob”列,您必须重新创建表。值得庆幸的是,有一种方法可以在 SSMS 中半自动执行此操作 - 通过更改表格“设计”窗口中的“文本文件组”,然后保存更改。
(从 2021 年开始快速更新):或者,您可以创建一个临时“分区”规则(分区规则是决定数据转到哪个文件组的函数),它将指向表中所有值的新文件组。应用此分区方案实际上会移动数据
如果您需要更多详细信息,我在这里写了博客:https ://www.jitbit.com/alexblog/153-moving-sql-table-textimage-to-a-new-filegroup/。
注意:将表移动到另一个文件组仅适用于企业版。
步骤1 :
检查哪个文件组表驻留在:
-- Query to check the tables and their current filegroup:
SELECT tbl.name AS [Table Name],
CASE WHEN dsidx.type='FG' THEN dsidx.name ELSE '(Partitioned)' END AS [File Group]
FROM sys.tables AS tbl
JOIN sys.indexes AS idx
ON idx.object_id = tbl.object_id
AND idx.index_id <= 1
LEFT JOIN sys.data_spaces AS dsidx
ON dsidx.data_space_id = idx.data_space_id
ORDER BY [File Group], [Table Name]
第2步 :
将现有表/表移动到新文件组
如果要将表格移动到的文件组不存在,请创建辅助文件组,然后移动表格。
要将表移动到不同的文件组,需要将表的聚集索引移动到新的文件组。聚集索引的叶级实际上包含了表数据。因此,可以使用 DROP_EXISTING 子句在单个语句中移动聚集索引,如下所示:
CREATE UNIQUE CLUSTERED INDEX [Index_Name] ON [SchemaName].[TableName]
(
[ClusteredIndexKeyFields]
)WITH (DROP_EXISTING = ON, ONLINE = ON) ON [FilegroupName]
GO
第 3 步:
将剩余的非聚集索引移动到辅助文件组
您必须使用下面提到的语法手动移动非聚集索引:
--1st check the index information using the following sp
sp_helpindex [YourTableName]
--Now by using the following query you can move the remaining indexes to secondary filegroup
CREATE NONCLUSTERED INDEX [Index_Name] ON [SchemaName].[TableName]
(
[IndexKeyFields]
)WITH (DROP_EXISTING = ON, ONLINE = ON) ON [FilegroupName]
GO
将堆移动到另一个文件组:
据我所知,将堆移动到另一个文件组的唯一方法是在新文件组上临时添加一个聚集索引,然后将其删除(如有必要)。
在SSMS中,展开Tables,展开你要移动的表,展开Indexes,右击聚集索引,点击“Script Index as”->“Drop and Create to”
这将打开一个带有脚本的查询窗口,以删除聚集索引并创建一个与原始索引具有相同规格的新索引。
在查询窗口中,在"ALTER TABLE <> ADD CONSTRAINT"
语句中,在语句末尾的“ON”关键字后更改文件组的名称,例如,如果表在 PRIMARY 文件组上,并且您想移动到名称为“SECONDARY”的文件组,则更"ON [PRIMARY]"
改为"ON [SECONDARY]"
.
如果您希望表在操作期间保持在线,请同时更改"ONLINE = OFF"
为"ONLINE = ON"
。
执行脚本,它将删除原始文件并在给定文件组中创建一个新文件。
我认为这些步骤非常简单直接,可以将任何表移动到不同的文件组(通过 Management Studio):
只需更改每个索引的 FileGroup 属性即可将所有非聚集索引移动到新文件组
将您的集群索引更改为非集群并简单地更改其文件组(如上一步)
通过此命令(或通过 IDE)使用“新文件组”添加新的临时集群索引:
CREATE CLUSTERED INDEX [PK_temp]
ON YOURTABLE([Id])
ON NEWFILEGROUP
(上述命令导致将所有数据移动到新文件组)
删除上述临时 PK(当它完美地完成工作时!)
将您的主集群索引再次更改为集群索引(再次通过 IDE)
上述步骤的好处是不需要删除现有的 FK 关系。使用 IDE 还可以防止在错误情况下丢失数据。
注意:确保没有为您的文件组启用磁盘配额或正确设置它。否则你会得到“文件组已满”异常!
CREATE CLUSTERED INDEX IXC_Products_Product_id
ON dbo.Products(Product_id)
WITH (DROP_EXISTING = ON) ON MyNewFileGroup
遇到了同样的问题,这是我想出的脚本(经过测试,可以正常工作):
DECLARE @Target_Filegroup sysname = N'XXX';
-----------------------------------------------------------------------------------------
;WITH [IX] AS(
SELECT
[Schema] = SCHEMA_NAME(so.[schema_id]) COLLATE DATABASE_DEFAULT,
[Object_Name] = so.[name] COLLATE DATABASE_DEFAULT,
[Object_Type] = so.[type],
[Is_Published] = so.[is_published],
[Is_Schema_Published] = so.[is_schema_published],
[IX_Name] = ix.[name] COLLATE DATABASE_DEFAULT,
[IX_Type] = ix.[type],
[IX_Type_Desc] = ix.[type_desc] COLLATE DATABASE_DEFAULT,
[Is_PK] = ix.[is_primary_key],
[Is_Unique] = ix.[is_unique],
[IX_Data_Space] = ds.[name] COLLATE DATABASE_DEFAULT,
[Is_UC] = ix.[is_unique_constraint],
[FF] = ix.[fill_factor],
[Is_Padded] = ix.[is_padded],
[Is_Disabled] = ix.[is_disabled],
[Is_Hypothetical] = ix.[is_hypothetical],
[Allow_Row_Locks] = ix.[allow_row_locks],
[Allow_Page_Locks] = ix.[allow_page_locks],
[Has_Filter] = ix.[has_filter],
[Filter] = ix.[filter_definition] COLLATE DATABASE_DEFAULT,
--[auto_created] = ix.[auto_created],
--[optimize_seq_key] = ix.[optimize_for_sequential_key],
[Indexed_Columns] = STUFF(( SELECT [text()] = CONCAT(', ', QUOTENAME(COL_NAME(ic.[object_id],ic.[column_id])))
FROM sys.index_columns ic
WHERE ic.[object_id] = so.[object_id]
AND ic.[index_id] = ix.[index_id]
AND ic.[is_included_column] = 0
ORDER BY ic.[key_ordinal]
FOR XML PATH('')
), 1, 2, '') COLLATE DATABASE_DEFAULT,
[Indexed_Columns_Order] = STUFF(( SELECT [text()] = CONCAT(', ', QUOTENAME(COL_NAME(ic.[object_id],ic.[column_id])), CASE [is_descending_key] WHEN 1 THEN ' DESC' ELSE ' ASC' END)
FROM sys.index_columns ic
WHERE ic.[object_id] = so.[object_id]
AND ic.[index_id] = ix.[index_id]
AND ic.[is_included_column] = 0
ORDER BY ic.[key_ordinal]
FOR XML PATH('')
), 1, 2, '') COLLATE DATABASE_DEFAULT,
[Included_Columns] = STUFF(( SELECT [text()] = CONCAT(', ', QUOTENAME(COL_NAME(ic.[object_id],ic.[column_id])))
FROM sys.index_columns ic
WHERE ic.[object_id] = so.[object_id]
AND ic.[index_id] = ix.[index_id]
AND ic.[is_included_column] = 1
ORDER BY ic.[key_ordinal]
FOR XML PATH('')
), 1, 2, '') COLLATE DATABASE_DEFAULT
FROM sys.objects so
LEFT JOIN sys.indexes ix ON so.[object_id] = ix.[object_id]
LEFT JOIN sys.data_spaces ds ON ix.[data_space_id] = ds.[data_space_id]
WHERE so.[type] IN ('U', 'V')
AND so.[is_ms_shipped] = 0
AND ix.[type] IS NOT NULL --| so we get heaps, and indexed views
)
SELECT
[Schema], [Object_Name], [Object_Type],
--[Is_Published], [Is_Schema_Published],
[IX_Name],
[IX_Data_Space],
[IX_Move_SQL] = CASE WHEN [IX_Data_Space] <> @Target_Filegroup AND [IX_Type] IN (1,2) THEN CONCAT(
'CREATE ', CASE [Is_Unique] WHEN 1 THEN 'UNIQUE ' END, [IX_Type_Desc], ' INDEX ', QUOTENAME([IX_Name]),
' ON ', QUOTENAME([Schema]), '.', QUOTENAME([Object_Name]), ' (', [Indexed_Columns_Order], ')',
CASE WHEN [Included_Columns] IS NOT NULL THEN CONCAT(' INCLUDE (', [Included_Columns], ')') END,
CASE WHEN [Has_Filter] = 1 THEN CONCAT(' WHERE ', [Filter]) END,
' WITH (PAD_INDEX=', CASE [Is_Padded] WHEN 1 THEN 'ON' ELSE 'OFF' END,
', FILLFACTOR=', CASE WHEN [FF] = 0 THEN '100' ELSE CAST([FF] as varchar(3)) COLLATE DATABASE_DEFAULT END,
', ALLOW_ROW_LOCKS=', CASE [Allow_Row_Locks] WHEN 1 THEN 'ON' ELSE 'OFF' END,
', ALLOW_PAGE_LOCKS=', CASE [Allow_Page_Locks] WHEN 1 THEN 'ON' ELSE 'OFF' END,
', DROP_EXISTING=ON ',')',
' ON ', QUOTENAME(@Target_Filegroup), ';')
END COLLATE DATABASE_DEFAULT
FROM [IX]
ORDER BY [Object_Type] ASC, [Schema] ASC , [Object_Name] ASC;