Quantcast
Channel: CodeSection,代码区,SQL Server(mssql)数据库 技术分享 - CodeSec
Viewing all articles
Browse latest Browse all 3160

Move SQL Server Tables to Different Filegroups

$
0
0

By:Sergey Gigoyan | Last Updated: 2018-12-14 || Related Tips:More > Database Administration

Problem

Sometimes it's necessary to move SQL Server tables between filegroups or create a copy of a table in a different filegroup. Reasons for having a copy of a table in a different filegroup could be for archiving historical data, using a copy of the table for reporting or for testing purposes. In this tip we will look at both scenarios and how it can be done using T-SQL.

Solution

This article will show methods of copying tables to another filegroup in SQL Server 2016/2017 and in older versions of SQL Server. It will also show how to use SELECT…INTO in SQL 2016 ((13.x) SP2) and 2017 to create tables in a different filegroup.

To illustrate the solution, a test environment is needed, so let's start with the creation of a test database.

Creating the test environment

The script below creates the TestDB database with two tables UserData and UserLog that stores login information. Both of these tables will be place in the default (primary) filegroup.

USE master
GO
--Database
CREATE DATABASE TestDB
GO
USE TestDB
GO
--Tables
CREATE TABLE UserData
(
UserID INT NOT NULL,
LoginName NVARCHAR(50),
PRIMARY KEY (UserID)
)
GO
CREATE TABLE UserLog
(
UserLogID INT NOT NULL IDENTITY(1,1),
UserID INT NOT NULL,
LoginDate DATETIME DEFAULT GETDATE(),
PRIMARY KEY (UserLogID)
)
GO
--Data
INSERT INTO UserData(UserID,LoginName)
VALUES(1,'<a href="/cdn-cgi/l/email-protection" data-cfemail="91e5fefcd1e5f4e2e5e4fff8e7f4e3e2f8e5e8bff2fefc">[email protected]</a>'),
(2,'<a href="/cdn-cgi/l/email-protection" data-cfemail="354654587541504641405b5c435047465c414c1b565a58">[email protected]</a> '),
(3,'<a href="/cdn-cgi/l/email-protection" data-cfemail="e68c878883a69283959293888f908394958f929fc885898b">[email protected]</a>'),
(4,'<a href="/cdn-cgi/l/email-protection" data-cfemail="c2a3acac82b6a7b1b6b7acabb4a7b0b1abb6bbeca1adaf">[email protected]</a>')
INSERT INTO UserLog(UserID)
VALUES(1),(2)
WAITFOR DELAY '00:00:10'
INSERT INTO UserLog(UserID)
VALUES(1),(3),(4)
WAITFOR DELAY '00:00:10'
INSERT INTO UserLog(UserID)
VALUES(2),(3),(1)

Now, we'll create a new filegroup to store historical data related to user logins. In other words, the UserData table (or some filtered data from that table) should be moved to a new filegroup.

So, let's create a new filegroup.

USE master
GO
ALTER DATABASE TestDB ADD FILEGROUP HISTORY
ALTER DATABASE TestDB
ADD FILE
(
NAME='History_Data',
FILENAME = 'D:\Microsoft SQL Server\mssql14.MSSQLSERVER\MSSQL\DATA\TesDB_2.mdf'
)
TO FILEGROUP HISTORY
GOGO

Running the query below, we can see that we have two filegroups for the database.

USE TestDB
GO
SELECT * FROM sys.filegroups
Move SQL Server Tables to Different Filegroups

However, both tables in our database are in the PRIMARY filegroup:

USE TestDB
GO
SELECT o.[name] AS TableName, i.[name] AS IndexName, fg.[name] AS FileGroupName
FROM sys.indexes i
INNER JOIN sys.filegroups fg ON i.data_space_id = fg.data_space_id
INNER JOIN sys.all_objects o ON i.[object_id] = o.[object_id]
WHERE i.data_space_id = fg.data_space_id AND o.type = 'U'
Move SQL Server Tables to Different Filegroups

Now, suppose we have a task to move the UserLog table to the HISTORY filegroup.

Moving a SQL Server table with data to a different filegroup Moving table with a clustered index

One solution to move a table to another filegroup is by dropping the clustered index and using the MOVE TO option as follows. We can see the IndexName in the above screenshot.

USE TestDB
GO
ALTER TABLE UserLog
DROP CONSTRAINT PK__UserLog__7F8B815172CE9EAE WITH (MOVE TO HISTORY)

We can now run this query to see which filegroup is being used.

USE TestDB
GO
SELECT o.[name] AS TableName, i.[name] AS IndexName, fg.[name] AS FileGroupName
FROM sys.indexes i
INNER JOIN sys.filegroups fg ON i.data_space_id = fg.data_space_id
INNER JOIN sys.all_objects o ON i.[object_id] = o.[object_id]
WHERE i.data_space_id = fg.data_space_id AND o.type = 'U'

We can see the UserLog table is now in the HISTORY filegroup. However, the table no longer has a clustered index. If you need a clustered index, you would need to create one for the UserLog table.


Move SQL Server Tables to Different Filegroups
Moving table without a clustered index

If we do not have a clustered index on the table, we can create a clustered index and specifying which filegroup to use.

For instance, if we want to move the UserLog table that we just moved to the HISTORY filegroup back to the PRIMARY filegroup, we could issue the following command.

USE TestDB
GO
CREATE UNIQUE CLUSTERED INDEX UIX_UserLogID
ON UserLog(UserLogID) ON [PRIMARY]

Run the following again.

USE TestDB
GO
SELECT o.[name] AS TableName, i.[name] AS IndexName, fg.[name] AS FileGroupName
FROM sys.indexes i
INNER JOIN sys.filegroups fg ON i.data_space_id = fg.data_space_id
INNER JOIN sys.all_objects o ON i.[object_id] = o.[object_id]
WHERE i.data_space_id = fg.data_space_id AND o.type = 'U'

We can see the UserLog table is back in the PRIMARY filegroup and has an index.


Move SQL Server Tables to Different Filegroups

If we do not need the clustered index, we would need to run additional code to drop it as follows.

USE TestDB
GO
DROP INDEX UserLog.UIX_UserLogID

Hence, if we are moving a heap to another filegroup, we first need to create a clustered index in order to move it to another filegroup and then we could drop the clustered index.

Creating a Copy of a SQL Server Table and Data on Different Filegroup

What if we don't want to move the table, but just create a copy in another filegroup.

Prior to SQL Server 2016 SP2

We could do this as follows where we use SELECT INTO, then create a clustered index and specify the filegroup, then drop the clustered index if we don't want the clustered index.

USE TestDB
GO
SELECT * INTO UserLogHistory FROM UserLog
CREATE UNIQUE CLUSTERED INDEX UIX_UserLogID
ON UserLogHistory(UserLogID) ON [HISTORY]
DROP INDEX UserLogHistory.UIX_UserLogID

As a result, we have a new table UserLogHistory in the HISTORY filegroup:

USE TestDB
GO
SELECT o.[name] AS TableName, i.[name] AS IndexName, fg.[name] AS FileGroupName
FROM sys.indexes i
INNER JOIN sys.filegroups fg ON i.data_space_id = fg.data_space_id
INNER JOIN sys.all_objects o ON i.[object_id] = o.[object_id]
WHERE i.data_space_id = fg.data_space_id AND o.type = 'U'
SELECT * FROM UserLogHistory
Move SQL Server Tables to Different Filegroups
SQL Server 2016 SP2 and later

Starting with SQL Server 2016 SP2, SELECT…INTO allows you tospecify a filegroup when creating the new table.

USE TestDB
GO
-- Create copy of the table and all data in different filegroup
SELECT * INTO UserLogHistory1 ON HISTORY
FROM UserLog

We can also use a WHERE clause to minimize the amount of data we want to move to the new table.

USE TestDB
GO
-- Create copy of the table and filtered data in different filegroup
SELECT * I

Viewing all articles
Browse latest Browse all 3160

Trending Articles