はじめに
同じサーバー上のあるボリュームから別のボリュームへのデータベースファイルまたはトランザクションログファイルの移動を保証する状況がいくつかあります。これらには次のものが含まれます:
- SQLServerのインストール時にボリュームが正しくフォーマットされていないと想定してボリュームをフォーマットする必要がある 。 SQL Serverをインストールするときは、64Kアロケーションユニットサイズを使用してボリュームをフォーマットすることをお勧めします。インストール時にこれを行わず、後で行う必要がある場合は、データベースの最初のバックアップを保持するか、適切にフォーマットされた新しいボリュームを作成して、データベースをこの新しいボリュームに移動する必要があります。
- 基盤となるストレージの制限に達したと想定して新しいボリュームを使用する必要がある 。良い例は、VMwareデータストアの2TBの制限です。これは、vSphere5.0以降の場合です。 vSphereの上位バージョンには、はるかに高い制限があります。
- IOを管理してパフォーマンスを向上させる必要性 。データファイルを移動するもう1つの理由は、パフォーマンスです。データベースが大きくなるにつれて、ストレージレイヤーに「ホットリージョン」を作成したことが明らかになるまで、すべてが1つのディスク上にある複数のデータファイルを使用してデータベースが作成される場合があります。 1つの解決策は、新しいデータファイルを作成してクラスター化インデックスを再構築することであり、別の解決策はデータファイルを移動することです。
シナリオ1:ユーザーデータベースの移動
ユーザーデータベースの移動に関連する手順には、次のものが含まれます。
- データベースをオフラインにします
- システムカタログを新しい場所で更新します
- データファイルを新しい場所に物理的にコピーします
- データベースをオンラインにする
リスト1は、これらのステップを実行するために実行されるコマンドを示しています。
1つの移動データファイルの一覧表示
-- 1. Run the following statement to check the current location of files. SELECT name, physical_name AS CurrentLocation, state_desc FROM sys.master_files WHERE database_id = DB_ID(N'BranchDB'); -- 2. Take the database offline. ALTER DATABASE BranchDB SET OFFLINE; -- 3. Move the file or files to the new location (at OS level). -- 4. For each file moved, run the following statement. ALTER DATABASE BranchDB MODIFY FILE ( NAME = WWI_UserData, FILENAME = 'N:\MSSQL\Data\WWI_UserDataNew.ndf' ); -- 5. Run the following statement. ALTER DATABASE BranchDB SET ONLINE; -- 6. Verify the file change by running the following query. SELECT name, physical_name AS CurrentLocation, state_desc FROM sys.master_files WHERE database_id = DB_ID(N'BranchDB');
データベースをオフラインにする場合、アクティブなセッションの数によってプロセスが遅延する可能性があることに注意してください。このタスクを実行するためにダウンタイムをスケジュールすることは良い考えです。このようなダウンタイムの間、アプリケーションの所有者は、DBAがデータベースをオフラインにしようとする前に、データベースへのアプリケーションサービスの接続を停止する必要があります。データベースをオフラインにするのがあまり便利ではない場合があります。その場合、インスタンスをシャットダウンするのが最善のオプションです。このような場合、アプローチは少し異なります。
- システムカタログを新しい場所で更新します
- インスタンスをシャットダウンします
- 目的のデータファイルを新しい場所に物理的にコピーします
- インスタンスを起動します
どちらのアプローチでも、概念は同じです。つまり、マスターデータベースのシステムカタログを更新してから、目的のデータファイルを物理的に再配置します。どちらの場合も、データファイルを完全に閉じる必要があります。最初のアプローチに含まれる手順を見てみましょう。
図1データファイルの場所の確認
最初のステップは、最初に物事の状態をチェックすることです。データベースをオフラインに設定し、システムカタログを変更します。
図2データベースをオフラインに設定してカタログを変更する
図3に示すように、カタログを更新すると、sys.master_filesにクエリを実行すると、ファイルを物理的に移動したかどうかに関係なく、マスターデータベースがデータファイルを予期する新しい場所がわかります。図4では、最初にファイルを新しい場所に物理的に移動せずにデータベースをオンラインにすることはできないこともわかります(そして、カタログで指定された新しい名前に一致するようにファイルの名前を変更します)。
図3新しいファイルの場所
図4不足しているファイル
また、ファイルをコピーすると、ファイルに対する以前のアクセス許可が失われ、データベースをオンラインにしようとしたときにSQLServerがファイルを開くことができなくなることも指摘しておきます。ファイルのアクセス許可を編集し、アカウントにファイルに対する完全なアクセス許可をNT SERVICE\MSSQLSERVERに追加する必要があります。
図5データファイルのコピー
図6宛先での権限
図7aソースでのアクセス許可
図7bソースでのアクセス許可
これらのアクセス許可がない状態でデータベースを再びオンラインにしようとすると、エラー0x5(アクセスが拒否されました)が発生します。エージェントジョブを使用してデータファイルを移動するようなことを行うと、SQL Serverエージェントアカウントがファイルの所有権を取得し、SQLServerエージェントアカウントがSQLServerアカウントと同じであるためにのみデータベースを取得できることがわかります。
図8新しいデータファイルで拒否されたアクセス
SSMS GUIを使用してデータベースをオンラインにしようとした場合、よく見ると、イベントビューアとSQLServerエラーログにこれらのエラーが表示されます。さらに、2番目のアプローチ(インスタンス全体を再起動する)を使用している場合は、データベースがリカバリ段階でスタックすることがわかります。エラーログを調べると、実際に何が起こっているのかがわかります。
エージェントジョブを使用した2つの移動データファイルの一覧表示
/* ==Scripting Parameters== Source Server Version : SQL Server 2017 (14.0.3023) Source Database Engine Edition : Microsoft SQL Server Standard Edition Source Database Engine Type : Standalone SQL Server Target Server Version : SQL Server 2017 Target Database Engine Edition : Microsoft SQL Server Standard Edition Target Database Engine Type : Standalone SQL Server */ USE [msdb] GO /****** Object: Job [MoveDataFile] Script Date: 7/12/2018 12:33:55 AM ******/ BEGIN TRANSACTION DECLARE @ReturnCode INT SELECT @ReturnCode = 0 /****** Object: JobCategory [[Uncategorized (Local)]] Script Date: 7/12/2018 12:33:56 AM ******/ IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name = N'[Uncategorized (Local)]' AND category_class = 1) BEGIN EXEC @ReturnCode = msdb.dbo.sp_add_category @class = N'JOB' ,@type = N'LOCAL' ,@name = N'[Uncategorized (Local)]' IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback END DECLARE @jobId BINARY(16) EXEC @ReturnCode = msdb.dbo.sp_add_job @job_name = N'MoveDataFile' ,@enabled = 1 ,@notify_level_eventlog = 0 ,@notify_level_email = 0 ,@notify_level_netsend = 0 ,@notify_level_page = 0 ,@delete_level = 0 ,@description = N'No description available.' ,@category_name = N'[Uncategorized (Local)]' ,@owner_login_name = N'sa' ,@job_id = @jobId OUTPUT IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback /****** Object: Step [MoveDataFile] Script Date: 7/12/2018 12:33:56 AM ******/ EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id = @jobId ,@step_name = N'MoveDataFile' ,@step_id = 1 ,@cmdexec_success_code = 0 ,@on_success_action = 1 ,@on_success_step_id = 0 ,@on_fail_action = 2 ,@on_fail_step_id = 0 ,@retry_attempts = 0 ,@retry_interval = 0 ,@os_run_priority = 0 ,@subsystem = N'PowerShell' ,@command = N'Copy-Item -Path M:\MSSQL\Data\WWI_UserData1.ndf N:\MSSQL\Data\WWI_UserData1.ndf' ,@database_name = N'master' ,@flags = 0 IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId ,@start_step_id = 1 IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId ,@server_name = N'(local)' IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback COMMIT TRANSACTION GOTO EndSave QuitWithRollback: IF (@@trancount > 0) ROLLBACK TRANSACTION EndSave: GO
図9エージェントジョブ使用時のデータファイルの権限
図10オンラインデータベース
プロセスの自動化
楽しみのために、プロセス全体でSQLServerエージェントジョブを使用することを決定できます。プロセスの各ステップにジョブステップを構成します。これは、スーパースターDBAになり、家に帰って家族とリラックスしながら、そのような移行を一晩スケジュールする場合に便利です。間違いなく、ジョブが成功したときに通知を発行するように構成して、不在中に実際に通知が実行されるようにする必要があります。
リスト3エージェントジョブを使用したタスクの実行
/* ==Scripting Parameters== Source Server Version : SQL Server 2017 (14.0.3023) Source Database Engine Edition : Microsoft SQL Server Standard Edition Source Database Engine Type : Standalone SQL Server Target Server Version : SQL Server 2017 Target Database Engine Edition : Microsoft SQL Server Standard Edition Target Database Engine Type : Standalone SQL Server */ USE [msdb] GO /****** Object: Job [MoveDataFile] Script Date: 7/12/2018 12:46:47 AM ******/ BEGIN TRANSACTION DECLARE @ReturnCode INT SELECT @ReturnCode = 0 /****** Object: JobCategory [[Uncategorized (Local)]] Script Date: 7/12/2018 12:46:47 AM ******/ IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name = N'[Uncategorized (Local)]' AND category_class = 1) BEGIN EXEC @ReturnCode = msdb.dbo.sp_add_category @class = N'JOB' ,@type = N'LOCAL' ,@name = N'[Uncategorized (Local)]' IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback END DECLARE @jobId BINARY(16) EXEC @ReturnCode = msdb.dbo.sp_add_job @job_name = N'MoveDataFile' ,@enabled = 1 ,@notify_level_eventlog = 0 ,@notify_level_email = 3 ,@notify_level_netsend = 0 ,@notify_level_page = 0 ,@delete_level = 0 ,@description = N'No description available.' ,@category_name = N'[Uncategorized (Local)]' ,@owner_login_name = N'sa' ,@notify_email_operator_name = N'DBA' ,@job_id = @jobId OUTPUT IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback /****** Object: Step [Set Database Offline] Script Date: 7/12/2018 12:46:47 AM ******/ EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id = @jobId ,@step_name = N'Set Database Offline' ,@step_id = 1 ,@cmdexec_success_code = 0 ,@on_success_action = 3 ,@on_success_step_id = 0 ,@on_fail_action = 2 ,@on_fail_step_id = 0 ,@retry_attempts = 0 ,@retry_interval = 0 ,@os_run_priority = 0 ,@subsystem = N'TSQL' ,@command = N'ALTER DATABASE BranchDB SET OFFLINE;' ,@database_name = N'master' ,@flags = 0 IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback /****** Object: Step [MoveDataFile] Script Date: 7/12/2018 12:46:47 AM ******/ EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id = @jobId ,@step_name = N'MoveDataFile' ,@step_id = 2 ,@cmdexec_success_code = 0 ,@on_success_action = 3 ,@on_success_step_id = 0 ,@on_fail_action = 2 ,@on_fail_step_id = 0 ,@retry_attempts = 0 ,@retry_interval = 0 ,@os_run_priority = 0 ,@subsystem = N'PowerShell' ,@command = N'Copy-Item -Path M:\MSSQL\Data\WWI_UserData1.ndf N:\MSSQL\Data\WWI_UserData1.ndf' ,@database_name = N'master' ,@flags = 0 IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback /****** Object: Step [ModifyFile and Bring Online] Script Date: 7/12/2018 12:46:47 AM ******/ EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id = @jobId ,@step_name = N'ModifyFile and Bring Online' ,@step_id = 3 ,@cmdexec_success_code = 0 ,@on_success_action = 1 ,@on_success_step_id = 0 ,@on_fail_action = 2 ,@on_fail_step_id = 0 ,@retry_attempts = 0 ,@retry_interval = 0 ,@os_run_priority = 0 ,@subsystem = N'TSQL' ,@command = N' ALTER DATABASE BranchDB MODIFY FILE ( NAME = WWI_UserData, FILENAME = ''N:\MSSQL\Data\WWI_UserDataNew.ndf'' ); ALTER DATABASE BranchDB SET ONLINE;' ,@database_name = N'master' ,@flags = 0 IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId ,@start_step_id = 1 IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId ,@server_name = N'(local)' IF (@@error <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback COMMIT TRANSACTION GOTO EndSave QuitWithRollback: IF (@@trancount > 0) ROLLBACK TRANSACTION EndSave: GO
結論
この記事では、SQLServerでユーザーデータベースファイルを移動する1つの方法を見てきました。また、データベースをオンラインに戻すときにエラーが発生しないように、新しい場所にあるデータファイルのアクセス許可に注意を払う必要があることもわかりました。また、T-SQLおよびPowerShellサブシステムを使用して、これらすべてをSQLServerエージェントジョブに配置できることも確認しました。次の記事では、データベースファイルを新しいボリュームに移動する他の2つの方法について説明します。
さらに読む:
SQL Serverでのデータファイルの移動–パート2