SQL Server 2008 Ent
和OLTP数据库
。我该如何在不中断服务的情况下将这些表移动到另一个filegroup
?目前,每秒钟在这些表中插入100-130条记录并更新30-50条记录。每个表约有1亿条记录和六个field
(包括一个geography
字段)。我正在Google中寻找解决方案,但所有的解决方案都包含:
我是否可以使用分区函数来解决这个问题?创建第二个表,从第一个表中插入行,删除第一个表等等
SQL Server 2008 Ent
和OLTP数据库
。我该如何在不中断服务的情况下将这些表移动到另一个filegroup
?目前,每秒钟在这些表中插入100-130条记录并更新30-50条记录。每个表约有1亿条记录和六个field
(包括一个geography
字段)。我是否可以使用分区函数来解决这个问题?创建第二个表,从第一个表中插入行,删除第一个表等等
如果您只想将表移动到新的文件组中,您需要在要移动到的新文件组上重新创建表的聚集索引(毕竟:聚集索引就是表数据)。
您可以使用以下方法执行此操作:
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]
这将创建一个新的聚集索引并删除现有的聚集索引,它会在你指定的文件组中创建新的聚集索引 - et voila,你的表数据已经移动到了新的文件组。
有关 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_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...
进行替换。
WITH (DROP_EXISTING = ON, ONLINE = ON)
,否则会出现“无效使用选项ONLINE”的错误。 - Alex from Jitbit分区是一种解决方案,但您可以使用以下方法将聚集索引“移动”到新文件组而不会中断服务(受某些条件的限制,请参见下面的链接):
CREATE CLUSTERED /*oops*/ INDEX ... WITH (DROP_EXISTING = ON, ONLINE = ON, ...) ON newfilegroup
聚集索引就是数据本身,这就像移动文件组一样。
请参见创建索引
这取决于你的主键是否为聚集索引,这会改变我们的操作方式。
CREATE *CLUSTERED* INDEX.....
才能实际移动数据,对吗? :-) - marc_sint、bit、datetime
等。varchar(max)、varbinary
和其他“blob”列,您需要重新创建表。值得庆幸的是,在SSMS中有一种半自动化的方法可以实现这一点——通过在表“设计”窗口中更改“文本文件组”,然后保存更改。
如果需要更多详细信息,请参阅我在此处的博客:https://www.jitbit.com/alexblog/153-moving-sql-table-textimage-to-a-new-filegroup/。(2021年的快速更新): 或者,您可以创建一个临时的“分区”规则(分区规则是决定数据存储在哪个文件组中的函数),将其指向表中所有值的新文件组。应用此分区方案实际上将移动数据。
在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"
。
执行该脚本,它将删除原始索引并在指定的文件组中创建一个新索引。
注意:将表移动到另一个文件组仅适用于企业版。
步骤 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
将堆移动到另一个文件组:
据我所知,将堆移动到另一个文件组的唯一方法是在新文件组上暂时添加聚集索引,然后再删除它(如果需要)。
我曾经遇到过同样的问题,这是我想出来的脚本(已测试,效果与您预期的一样):
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;
我认为这些步骤非常简单明了,可以通过管理工具将任何表移动到不同的文件组中:
通过更改每个索引的FileGroup属性,将所有非聚集索引移动到新的文件组中
像上一步骤一样,将您的聚集索引更改为非聚集,并更改其文件组
通过此命令(或通过IDE)在“新文件组”中添加一个新的临时聚集索引:
CREATE CLUSTERED INDEX [PK_temp]
ON YOURTABLE([Id])
ON NEWFILEGROUP
(以上命令会导致将所有数据移动到新的文件组中)
删除上述临时PK(当它完美地完成其工作时!)
再次通过IDE将主要聚集索引更改为聚集索引
CREATE CLUSTERED INDEX IXC_Products_Product_id
ON dbo.Products(Product_id)
WITH (DROP_EXISTING = ON) ON MyNewFileGroup
create table(... constraint(...) on FG1 ) ON FG2
- FG1 优先级更高。感谢您的帮助。 - WernerCD