[Sample] えす!エス!レスキュー SQL Server -どっぷりリファレン中!!- Vol. 1
◆◇◇◆━━━━━━━━━━━━━━━━━━━━2009.06.10━━━・‥… えす!エス!レスキュー SQL Server -どっぷりリファレン中!!- ・‥…━━━━━━━━━━━━━━━━━━━━━Vol. 1━━━━◆◇◇◆<<目次>>■SQL Server リファレン中!! その1■お知らせ・・・○ご質問について■編集者より┏─────────────────────────────────┓┃SQL Server リファレン中!! ┃┗─────────────────────────────────┛インサイトテクノロジーがお送りする、SQL Serverのメルマガ「えす!エス!レスキュー SQL Server -どっぷりリファレン中!!-」第1弾をお届けします!!このメルマガでお送りする情報は以下のエディションをターゲットにし、記載しております。ターゲット : SQL Server 2008 Enterprise Edition x86Enterprise Editionが高い!と思われるかも知れませんが、180日間限定のトライアル版を、以下のサイトからダウンロードできますのでぜひ、メルマガを見つつ、色々と試していただけたらと思います。SQL Server 2008 の評価版ダウンロードページhttps://www.microsoft.com/japan/SQLServer/2008/downloads/default.mspxこのSQLServerのメルマガは、夏椰(かや)がお送りします。最初なので、簡単に自己紹介をさせてください。歳は30歳です。(2009年06月現在)身長は166cm、基礎代謝が1400kcalぐらいです。ソフトテニスと一眼レフが趣味です。データベースも趣味だったのですが、インサイトテクノロジーに入社し、お仕事になりました♪そして、こうして皆様にメルマガという形で私の知っていることや、チャレンジしたことをお届けする機会を得る事が出来、嬉しく思っています。では、本題へ。今回のSQL Server - どっぷりリファレン中では、SQL Serverにおける「データファイル」と「ページ」、「エクステント」について見ていきます。====================================================================== アジェンダ====================================================================== 今回のメルマガでは以下の内容をお伝えします。 1) データファイルとページ 2) データベースとデータファイル・ページ ・ ページの種類 ・ ページとエクステントの関係 ・ テーブルとページの関係 4) データファイルとエクステント====================================================================== データファイルとページ ======================================================================SQL ServerでもOracleでも、データはデータファイルに格納されていきます。そのデータファイルの中身はどうなっているんでしょうか?まず最初に、接続中のインスタンスが使っているファイルの一覧を取得し、表示します。<< SQL文 >>/********************************************************************/SELECT * FROM sys.master_files;/********************************************************************/# sys.master_filesについては MSDNライブラリ参照。# https://msdn.microsoft.com/ja-jp/library/ms186782.aspx<< 実行結果(抜粋) >>/********************************************************************/database_id file_id type type_desc name----------- ----------- ---- ---------- ------------------------------1 1 0 ROWS master1 2 1 LOG mastlog2 1 0 ROWS tempdev2 2 1 LOG templog3 1 0 ROWS modeldev3 2 1 LOG modellog4 1 0 ROWS MSDBData4 2 1 LOG MSDBLog5 1 0 ROWS ReportServer5 2 1 LOG ReportServer_log6 1 0 ROWS ReportServerTempDB6 2 1 LOG ReportServerTempDB_log7 1 0 ROWS test7 2 1 LOG test_log/********************************************************************/# 実行結果 https://www.insight-tec.com/mailmagazine/SQL_ref/sys.master_files.png/********************************************************************/この結果を見て分るように、 ・行データが入るファイル ・ログデータが入るファイルの2種類のファイルが存在していることが分るかと思います。sys.master_filesが出力する列数は多く、様々な情報が入っていますのでファイルサイズと必要な情報がある程度見えるように、出力列を絞って、SQLを実行していきます。また、4つの列に対し、式を入れていきます。max_size列が-1の場合、ファイルの最大値は可能サイズまで増加するという"無制限"指定なので、max_size列が0以下の場合は、"無制限"と表示されるようにしました。growth列は0の場合、サイズの増減がない固定ファイルサイズになりますのでその場合には、"固定"と表示されるようにしました。そして、growth列の値はis_percent_growthの値が1の場合はパーセント(%)、それ以外はページ数を示していますので、is_percent_growth列の値を見て、growthの増え方がどちらなのか、"%"と"page(s)"という"単位"を付加して表示するようにしました。DB_NAMEという関数を使い、database_idに対応するデータベースの名前が表示されるようにしました。# MSDN https://msdn.microsoft.com/ja-jp/library/ms189753.aspxそれでは、組みあがったSQL文と実行結果を記載します。<< SQL文 >>/********************************************************************/SELECT DB_NAME(database_id) dbname, name, file_id, file_guid, physical_name, size, case when max_size < 0 then N'無制限' else CAST(max_size as nvarchar) end max_size, case when growth = 0 then N'固定' else CAST(growth as nvarchar) end + case when is_percent_growth = 1 then N'%' else N'page(s)' end growth FROM sys.master_files;/********************************************************************/<< 実行結果(抜粋) >>/********************************************************************/dbname physical_name ------ ------------------------------------------------------------master C:\SQL ServerData\MSSQL10.MSSQL Server\MSSQL\DATA\master.mdf master C:\SQL ServerData\MSSQL10.MSSQL Server\MSSQL\DATA\mastlog.ldf tempdb C:\SQL ServerData\MSSQL10.MSSQL Server\MSSQL\DATA\tempdb.mdf tempdb C:\SQL ServerData\MSSQL10.MSSQL Server\MSSQL\DATA\templog.ldf model C:\SQL ServerData\MSSQL10.MSSQL Server\MSSQL\DATA\model.mdf size max_size growth ----- -------- ---------- 512 無制限 10% 160 無制限 10% 1024 無制限 10% 64 無制限 10% 288 無制限 128page(s) /********************************************************************/# 実行結果 https://www.insight-tec.com/mailmagazine/SQL_ref/sys.master_files_change1.png/********************************************************************/ここから、結果の中にある1つのファイルをピックアップして情報を見ていきます。1行目にあるmasterというデータベースのsizeには"512"と出力されています。しかし、physical_nameで指定されているファイルのプロパティをみると、実際のファイルサイズは4,194,304 バイトです。# https://www.insight-tec.com/mailmagazine/SQL_ref/master.mdf.pngでは、SQLの結果で出力された"512"は何を示しているのでしょうか?sys.master_filesの説明を見ると"size列は、現在のファイル サイズ (8 KB ページ単位) "とあります。よってこの512は、「8KBのページ数が512個はいっています。」といっているわけです。試しに、先ほどのsize部分がバイトで出力されるように修正します。<< SQL文 >>/********************************************************************/SELECT DB_NAME(database_id) dbname, name, file_id, file_guid, physical_name, cast(size as decimal) *8*1024 [size], case when max_size < 0 then N'無制限' else CAST(max_size as nvarchar) end max_size, case when growth = 0 then N'固定' else CAST(growth as nvarchar) end + case when is_percent_growth = 1 then N'%' else N'page(s)' end growth FROM sys.master_files;/********************************************************************/<< 実行結果(抜粋) >>/********************************************************************/dbname physical_name ------ ----------------------------------------------------------- master C:\SQL ServerData\MSSQL10.MSSQL Server\MSSQL\DATA\master.mdf master C:\SQL ServerData\MSSQL10.MSSQL Server\MSSQL\DATA\mastlog.ldf tempdb C:\SQL ServerData\MSSQL10.MSSQL Server\MSSQL\DATA\tempdb.mdf tempdb C:\SQL ServerData\MSSQL10.MSSQL Server\MSSQL\DATA\templog.ldf model C:\SQL ServerData\MSSQL10.MSSQL Server\MSSQL\DATA\model.mdf size max_size growth------- -------- ----------4194304 無制限 10%1310720 無制限 10%8388608 無制限 10%524288 無制限 10%2359296 無制限 128page(s)/********************************************************************/# 実行結果 https://www.insight-tec.com/mailmagazine/SQL_ref/sys.master_files_change2.png/********************************************************************/これで、ファイルのプロパティで表示されていたファイルサイズとSQL出力結果のsizeが一致し、SQL Serverのページが8KBである事を実感できたかと思います。====================================================================== データベースとデータファイル・ページ======================================================================先ほどまでの検証にて、データファイルの中には"ページ"というものが存在している事を感じていただけたかと思います。今度はそのページとは何かをみていきます。事前準備として、使用するデータベースとテーブルを作成します。<< SQL文 >>/********************************************************************/USE [master]GOCREATE DATABASE mini ON PRIMARY ( NAME = N'miniPri', FILENAME = N'C:\SQL ServerData\miniPri.mdf' , SIZE = 3MB , FILEGROWTH = 1KB),FILEGROUP miniSec DEFAULT ( NAME = N'miniSec', FILENAME = N'C:\SQL ServerData\miniSec.mdf' , SIZE = 512KB , FILEGROWTH = 1KB)LOG ON ( NAME = N'log', FILENAME = N'C:\SQL ServerData\mini.ldf' )GoUSE [mini]GOCREATE TABLE [tb1]( [id] [decimal](18, 0) NOT NULL, [col1] [nvarchar](4000) NULL, [col2] [nvarchar](max) NULL, [col3] [nvarchar](max) NULL, CONSTRAINT [pktb1] PRIMARY KEY CLUSTERED ( [id] ASC )ON [miniSec]) ON [miniSec]GO/********************************************************************/ここでさらっと"エクステント"について記述します。詳しくは、これ以降に記載しますが、CREATE DATABASEで指定するFILEGROWTHの値は、『指定したサイズを、最も近い 64 KB 単位の値に切り上げた数値』が実際の設定値として適用されます。領域の増加は"エクステント単位"で行われるのですが、8ページ=1エクステント、1ページ=8KBと決まっているからです。よって、増加の最小値が 8KB * 8 = 64KB になる・・・ということを暗に示しています。さて、話を元に戻しまして、作成しただけの状態で、このデータベースのサイズを調べてみます。次のSQLはデータベースに割り当てられたデータ領域を表示するSQLです。<< SQL文 >>/********************************************************************/USE [mini]GOSELECT *FROM sys.data_spaces;/********************************************************************/# MSDN https://msdn.microsoft.com/ja-jp/library/ms190289.aspx<< 実行結果 >>/********************************************************************/name data_space_id type type_desc is_default------- ------------- ---- -------------- ----------PRIMARY 1 FG ROWS_FILEGROUP 0miniSec 2 FG ROWS_FILEGROUP 1/********************************************************************/この結果により、CREATE DATABASEのON以下で指定した"PRIMARY"というファイルグループと"miniSec"というファイルグループが表示されます。次に、このデータベースのアロケーションユニットの一覧を取得してみます。# アロケーションユニットについてはMSDNライブラリ参照# MSDN https://msdn.microsoft.com/ja-jp/library/ms189051.aspx<< SQL文 >>/********************************************************************/USE [mini]GOSELECT *FROM sys.allocation_units;/********************************************************************/# MSDN https://msdn.microsoft.com/ja-jp/library/ms189792.aspx<< 実行結果(抜粋) >>/********************************************************************/allocation_unit_id type type_desc container_id ------------------ ---- ----------------- ------------------72057594039828480 1 IN_ROW_DATA 72057594038779904 72057594039894016 3 ROW_OVERFLOW_DATA 72057594038779904 72057594039959552 2 LOB_DATA 72057594038779904 data_space_id total_pages used_pages data_pages ------------- ----------- ---------- ---------- 2 0 0 0 2 0 0 0 2 0 0 0/********************************************************************/このSQL結果は100件強出力されているかと思います。この出力結果が、ページの集合体であるアロケーションユニットの一覧結果になるのですが、これだけを見ていても、情報がよく見えないと思いますので、SQLを改変し、実行します。<< SQL文 >>/********************************************************************/USE [mini]GOSELECT sys.allocation_units.allocation_unit_id, sys.allocation_units.type_desc, sys.allocation_units.total_pages, sys.allocation_units.used_pages, sys.allocation_units.data_pages, sys.partitions.object_id, OBJECT_NAME(sys.partitions.object_id) object_desc, sys.partitions.index_id, sys.partitions.rowsFROM sys.data_spaces join ( sys.allocation_units left outer join sys.partitions ON container_id = CASE WHEN sys.allocation_units.type % 2 = 1 THEN sys.partitions.hobt_id WHEN sys.allocation_units.type = 2 THEN sys.partitions.partition_id END ) ON sys.data_spaces.data_space_id = sys.allocation_units.data_space_idORDER BY object_id;/********************************************************************/<< 実行結果(抜粋) >>/********************************************************************/allocation_unit_id type_desc total_pages used_pages -------------------- ----------------- ----------- ----------- 72057594039828480 IN_ROW_DATA 0 0 72057594039894016 ROW_OVERFLOW_DATA 0 0 72057594039959552 LOB_DATA 0 0 data_pages object_id object_desc index_id rows---------- ----------- ----------- -------- -----0 2105058535 tb1 1 00 2105058535 tb1 1 00 2105058535 tb1 1 0/********************************************************************/これでどのオブジェクトが、どれぐらいの行数があり、どれぐらいページを使用しているかが分るようになりました。さらに突っ込んで、これをファイル/ファイルグループと繋げてみます。<< SQL文 >>/********************************************************************/USE [mini]GOSELECT sys.data_spaces.*, sys.allocation_units.allocation_unit_id, sys.allocation_units.type_desc, sys.allocation_units.total_pages, sys.allocation_units.used_pages, sys.allocation_units.data_pages, sys.partitions.object_id, OBJECT_NAME(sys.partitions.object_id) object_desc, sys.partitions.index_id, sys.partitions.rowsFROM sys.data_spaces join ( sys.allocation_units left outer join sys.partitions ON container_id = CASE WHEN sys.allocation_units.type % 2 = 1 THEN sys.partitions.hobt_id WHEN sys.allocation_units.type = 2 THEN sys.partitions.partition_id END ) ON sys.data_spaces.data_space_id = sys.allocation_units.data_space_idORDER BY object_id;/********************************************************************/<< 実行結果(抜粋) >>/********************************************************************/name data_space_id type type_desc is_default ------- ------------- ---- -------------- ---------- miniSec 2 FG ROWS_FILEGROUP 1 miniSec 2 FG ROWS_FILEGROUP 1 miniSec 2 FG ROWS_FILEGROUP 1 allocation_unit_id type_desc total_pages used_pages data_pages------------------ ----------------- ----------- ---------- ----------72057594039828480 IN_ROW_DATA 0 0 0 72057594039894016 ROW_OVERFLOW_DATA 0 0 0 72057594039959552 LOB_DATA 0 0 0 object_id object_desc index_id rows----------- ----------- -------- ----2105058535 tb1 1 02105058535 tb1 1 02105058535 tb1 1 0/********************************************************************/これで、ファイル/ファイルグループに格納されているページ数がいくつか、格納されているオブジェクトが何で、どれぐらいの行数あるのかが見えるようになりました。ここでテーブルに1行データをいれて、先ほどのSQLを再度実行してみたいと思います。<< SQL文 >>/********************************************************************/insert into tb1 values ( 1, null, null, null);/********************************************************************/<< 実行結果(抜粋) >>/********************************************************************/name data_space_id type type_desc is_default ------- ------------- ---- -------------- ---------- miniSec 2 FG ROWS_FILEGROUP 1 miniSec 2 FG ROWS_FILEGROUP 1 miniSec 2 FG ROWS_FILEGROUP 1 allocation_unit_id type_desc total_pages used_pages data_pages ------------------ ----------------- ----------- ---------- ---------- 72057594039828480 IN_ROW_DATA 2 2 172057594039894016 ROW_OVERFLOW_DATA 0 0 072057594039959552 LOB_DATA 0 0 0object_id object_desc index_id rows----------- ----------- -------- ----2105058535 tb1 1 12105058535 tb1 1 12105058535 tb1 1 1/********************************************************************/データを1行追加した事で、tb1のIN_ROW_DATAが使用しているページの数が2に増えました。行データで1ページ、nvarcharが格納されるページで1ページ使用しているので、計2ページの使用になります。さらに、1行追加して再実行します。<< SQL文 >>/********************************************************************/insert into tb1 values ( 2, null, null, null);/********************************************************************/ << 実行結果(抜粋) >>/********************************************************************/name data_space_id type type_desc is_default ------- ------------- ---- -------------- ---------- miniSec 2 FG ROWS_FILEGROUP 1 miniSec 2 FG ROWS_FILEGROUP 1 miniSec 2 FG ROWS_FILEGROUP 1 allocation_unit_id type_desc total_pages used_pages data_pages------------------ ----------------- ----------- ---------- ----------72057594039828480 IN_ROW_DATA 2 2 172057594039894016 ROW_OVERFLOW_DATA 0 0 072057594039959552 LOB_DATA 0 0 0object_id object_desc index_id rows----------- ----------- -------- ----2105058535 tb1 1 22105058535 tb1 1 22105058535 tb1 1 2/********************************************************************/今度は格納行数が2行に増えましたが、使用ページ数は増えていません。よって、1ページには複数行のデータが格納されていることが分ります。次に、tb1.col1に大きいバイト数のデータをUpdateをして、再実行します。<< SQL文 >>/********************************************************************/USE [mini]GOUPDATE tb1 SET col1 = REPLICATE(N'~', 4000);GOSELECT DATALENGTH(col1) col1_len FROM tb1WHERE id = 1; USE [mini]GOSELECT id, DATALENGTH(col1) col1_len FROM tb1; SELECT sys.data_spaces.*, sys.allocation_units.allocation_unit_id, sys.allocation_units.type_desc, sys.allocation_units.total_pages, sys.allocation_units.used_pages, sys.allocation_units.data_pages, sys.partitions.object_id, OBJECT_NAME(sys.partitions.object_id) object_desc, sys.partitions.index_id, sys.partitions.rowsFROM sys.data_spaces join ( sys.allocation_units left outer join sys.partitions ON container_id = CASE WHEN sys.allocation_units.type % 2 = 1 THEN sys.partitions.hobt_id WHEN sys.allocation_units.type = 2 THEN sys.partitions.partition_id END ) ON sys.data_spaces.data_space_id = sys.allocation_units.data_space_idORDER BY data_space_id;/********************************************************************/<< 実行結果(抜粋) >>/********************************************************************/name data_space_id type type_desc is_default ------- ------------- ---- -------------- ---------- miniSec 2 FG ROWS_FILEGROUP 1 miniSec 2 FG ROWS_FILEGROUP 1 miniSec 2 FG ROWS_FILEGROUP 1 allocation_unit_id type_desc total_pages used_pages data_pages------------------ ----------------- ----------- ---------- ----------72057594039828480 IN_ROW_DATA 4 4 272057594039894016 ROW_OVERFLOW_DATA 0 0 072057594039959552 LOB_DATA 0 0 0object_id object_desc index_id rows----------- ----------- -------- ----2105058535 tb1 1 22105058535 tb1 1 22105058535 tb1 1 2/********************************************************************/今度はtb1.col1のバイト数8,000バイト×2になったので、1ページ(8KB)に格納きしれず、tb1のIN_ROW_DATAが使用しているページ数が増えました。同様にtb1.col2に大きいバイト数のデータをUpdateをして、再実行します。<< SQL文 >>/********************************************************************/UPDATE tb1 SET col2 = REPLICATE(N'~', 4000);USE [mini]GOSELECT id, DATALENGTH(col1) col1_len, DATALENGTH(col2) col2_len FROM tb1; SELECT sys.data_spaces.*, sys.allocation_units.allocation_unit_id, sys.allocation_units.type_desc, sys.allocation_units.total_pages, sys.allocation_units.used_pages, sys.allocation_units.data_pages, sys.partitions.object_id, OBJECT_NAME(sys.partitions.object_id) object_desc, sys.partitions.index_id, sys.partitions.rowsFROM sys.data_spaces join ( sys.allocation_units left outer join sys.partitions ON container_id = CASE WHEN sys.allocation_units.type % 2 = 1 THEN sys.partitions.hobt_id WHEN sys.allocation_units.type = 2 THEN sys.partitions.partition_id END ) ON sys.data_spaces.data_space_id = sys.allocation_units.data_space_idORDER BY data_space_id;/********************************************************************/<< 実行結果(抜粋) >>/********************************************************************/name data_space_id type type_desc is_default ------- ------------- ---- -------------- ---------- miniSec 2 FG ROWS_FILEGROUP 1 miniSec 2 FG ROWS_FILEGROUP 1 miniSec 2 FG ROWS_FILEGROUP 1 allocation_unit_id type_desc total_pages used_pages data_pages------------------ ----------------- ----------- ---------- ----------72057594039828480 IN_ROW_DATA 4 4 272057594039894016 ROW_OVERFLOW_DATA 0 0 072057594039959552 LOB_DATA 3 3 0object_id object_desc index_id rows----------- ----------- -------- ----2105058535 tb1 1 22105058535 tb1 1 22105058535 tb1 1 2/********************************************************************/今度はtb1.col2のバイト数8,000バイト×2になったので、1ページ(8KB)に格納きしれず、tb1のLOB_DATAが使用しているページ数が増えました。これは、tb1.col1 = nvarchar(4000) と定義されているのに対して、tb1.col2 = nverchar(max)と定義されている違いです。max指定をするとLOBと同じ様にデータが扱われ、LOBとしてページが確保されることが分ります。同様にtb1.col3の値も同じ様にUpdateすると、結果が以下のようになります。<< 実行結果(抜粋) >>/********************************************************************/name data_space_id type type_desc is_default ------- ------------- ---- -------------- ---------- miniSec 2 FG ROWS_FILEGROUP 1miniSec 2 FG ROWS_FILEGROUP 1miniSec 2 FG ROWS_FILEGROUP 1allocation_unit_id type_desc total_pages used_pages data_pages------------------ ----------------- ----------- ---------- ----------72057594039828480 IN_ROW_DATA 4 4 272057594039894016 ROW_OVERFLOW_DATA 3 3 072057594039959552 LOB_DATA 5 5 0object_id object_desc index_id rows----------- ----------- -------- ----2105058535 tb1 1 22105058535 tb1 1 22105058535 tb1 1 2/********************************************************************/この様に、ページには複数行格納されているものもあれば、複数ページで1つのデータを格納しているものもあります。このあたりの詳細はMSDNを参照すると、より理解できるかと思います。ページとエクステントについて MSND https://msdn.microsoft.com/ja-jp/library/ms190969.aspx参照:8 KB を超える場合の行オーバーフロー データMSND https://msdn.microsoft.com/ja-jp/library/ms186981.aspx====================================================================== データファイルとエクステント======================================================================ここで話を最初のデータファイルの方に戻します。このminiというデータベースを作成し、tb1というテーブルを作成、レコード2件登録、col1, col2, col3とUpdateしてきました。ここまでの状態で、mini.dbo.tb1がデータを格納するために使用しているファイルのサイズは524,288 バイトになっていました。この状態から、データをこのままで1件ずつ増やしていきたいと思います。<< SQL文 >>/********************************************************************/INSERT INTO tb1SELECT id + 1, col1, col2, col3 FROM tb1 WHERE id = ( SELECT MAX(id) FROM tb1 );/********************************************************************/このSQLを何度も発行し、最初にデータの増減があった17行目でデータファイルのサイズやデータベースのページ数を取得してみます。<< SQL文 >>/********************************************************************/SELECT sys.data_spaces.*, sys.allocation_units.allocation_unit_id, sys.allocation_units.type_desc, sys.allocation_units.total_pages, sys.allocation_units.used_pages, sys.allocation_units.data_pages, sys.partitions.object_id, OBJECT_NAME(sys.partitions.object_id) object_desc, sys.partitions.index_id, sys.partitions.rowsFROM sys.data_spaces join ( sys.allocation_units left outer join sys.partitions ON container_id = CASE WHEN sys.allocation_units.type % 2 = 1 THEN sys.partitions.hobt_id WHEN sys.allocation_units.type = 2 THEN sys.partitions.partition_id END ) ON sys.data_spaces.data_space_id = sys.allocation_units.data_space_idORDER BY data_space_id;SELECT DB_NAME(database_id) dbname, name, file_id, file_guid, physical_name, cast(size as decimal) *8*1024 [size], case when max_size < 0 then N'無制限' else CAST(max_size as nvarchar) end max_size, case when growth = 0 then N'固定' else CAST(growth as nvarchar) end + case when is_percent_growth = 1 then N'%' else N'page(s)' end growth FROM sys.master_files;/********************************************************************/<< 実行結果(抜粋) >>/********************************************************************/name data_space_id type type_desc is_default ------- ------------- ---- -------------- ---------- miniSec 2 FG ROWS_FILEGROUP 1miniSec 2 FG ROWS_FILEGROUP 1miniSec 2 FG ROWS_FILEGROUP 1allocation_unit_id type_desc total_pages used_pages data_pages------------------ ----------------- ----------- ---------- ----------72057594039828480 IN_ROW_DATA 4 4 272057594039894016 ROW_OVERFLOW_DATA 25 18 072057594039959552 LOB_DATA 41 35 0object_id object_desc index_id rows----------- ----------- -------- ----2105058535 tb1 1 172105058535 tb1 1 172105058535 tb1 1 17======================================================================dbname physical_name size max_size growth------ ---------------------------- ------- -------- ----------mini C:\SQL ServerData\miniSec.mdf 655360 無制限 8page(s)/********************************************************************/ファイルサイズが524288バイトから655360バイトへ増加しました。これによって増加したページ数は128ページ、増加したエクステント数は16エクステントだと分ります。(655360 - 524288)/8192 = 16ページ16 / 8 = 2 エクステント次はINSERTのデータを少なくして、増加をみてみます。<< SQL文 >>/********************************************************************/INSERT INTO tb1SELECT id + 1, col1, null, nullFROM tb1 WHERE id = ( SELECT MAX(id) FROM tb1 );/********************************************************************/このSQLを何度も発行し、最初にデータの増減があった状態は以下のようになります。<< 実行結果(抜粋) >>/********************************************************************/name data_space_id type type_desc is_default ------- ------------- ---- -------------- ---------- miniSec 2 FG ROWS_FILEGROUP 1miniSec 2 FG ROWS_FILEGROUP 1miniSec 2 FG ROWS_FILEGROUP 1allocation_unit_id type_desc total_pages used_pages data_pages------------------ ----------------- ----------- ---------- ----------72057594039828480 IN_ROW_DATA 7 7 572057594039894016 ROW_OVERFLOW_DATA 25 18 072057594039959552 LOB_DATA 41 35 0object_id object_desc index_id rows----------- ----------- -------- ----2105058535 tb1 1 202105058535 tb1 1 202105058535 tb1 1 20dbname physical_name size max_size growth------ ---------------------------- ------- -------- ----------mini C:\SQL ServerData\miniSec.mdf 720896 無制限 8page(s)/********************************************************************/ファイルサイズが655360バイトから720896バイトへ増加しました。これによって増加したページ数は8ページ、増加したエクステント数は1エクステントだと分ります。これまでの、データ増加は1ページより大きいデータを追加してきました。では、1ページ未満のデータを数件いれて増加量を見てみようと思います。<< SQL文 >>/********************************************************************/INSERT INTO tb1SELECT ( SELECT MAX(id) FROM tb1 ) + 1, REPLICATE(N'0',1000), null, null;/********************************************************************/このSQLを何度も発行し、最初にデータの増減があった状態は以下のようになります。<< 実行結果(抜粋) >>/********************************************************************/name data_space_id type type_desc is_default ------- ------------- ---- -------------- ---------- miniSec 2 FG ROWS_FILEGROUP 1miniSec 2 FG ROWS_FILEGROUP 1miniSec 2 FG ROWS_FILEGROUP 1allocation_unit_id type_desc total_pages used_pages data_pages------------------ ----------------- ----------- ---------- ----------72057594039828480 IN_ROW_DATA 17 10 872057594039894016 ROW_OVERFLOW_DATA 25 18 072057594039959552 LOB_DATA 41 35 0object_id object_desc index_id rows----------- ----------- -------- ----2105058535 tb1 1 292105058535 tb1 1 292105058535 tb1 1 29dbname physical_name size max_size growth------ ---------------------------- ------- -------- ----------mini C:\SQL ServerData\miniSec.mdf 786432 無制限 8page(s)/********************************************************************/ ファイルサイズが720896バイトから786432バイトへ増加しました。これによって増加したページ数は8ページ、増加したエクステント数は1エクステントだと分ります。なぜ、この8ページで増加するのかというと、CREATE DATABASEで指定したFILEGROWTH=1KBがSQL Serverによって、1KBから最も近い64 KB 単位の値に切り上げられて増加するからです。よって、ファイルサイズの最小増加は8ページ単位になります。====================================================================== まとめ と 考察====================================================================== ・ データベースにはデータが格納されるデータファイルと、 ログが格納されるログファイルとを持っている。 -> これによって、SQL Serverはデータベースごとに ログファイルを持つ構造になっていることがわかる。 よって、インスタンス毎ではなく、 データベース毎のバックアップ & 復旧が行われる必要がある。 ・ データベースはページという単位を持っていて ページはデータファイルの中に書きこまれる最小単位である。 また、ページにはテーブルのデータが格納されていて、 1ページに複数行格納されている。 ただし、8KBを超えるデータの場合、 ページをまたがってデータが格納される。 -> 1ページは8KBという制限があるので、 列長を8KBよりも大きくするときは、性能面での考慮が必要。 (ページ毎にバッファへのデータ入出力が行われるため) ・ データが格納できるページが無くなると、ファイルの拡張が発生する。 また、データファイルは最小64KB単位で増えていく。 よって、8ページ=1エクステント単位で増えていく。 -> SQL Serverのデータファイルを格納するディスクが データ増加により、知らない間に圧迫されないか 気を払う必要がある。 特に、無制限拡張をしている場合は 使えるだけどんどんファイルサイズが増加するので注意が必要。 ・ データファイルには、ファイルとグループの2種類がある。 -> ファイルグループを使い、実ファイルを 複数ディスクに分散させることが出来る。┏─────────────────────────────────┓┃ご質問について ┃┗─────────────────────────────────┛<皆様からのご質問を受付けております>皆様のご質問にはできるだけ、お答えしたいと思っています。すべてのご質問にお答えすることはできないかもしれませんが、適宜メルマガ内でとりあげていく予定ですので、是非お気軽に下記アドレスまでお寄せください。ご意見、ご感想などもお待ちしておりますっ!!wlmailhtml:{FFB7FEE3-FD66-4A13-AECC-755EBDF825BF}mid://00000000/!x-usc:mailto:letter\@insight-tec.co.jp┏─────────────────────────────────┓┃編集者より ┃┗─────────────────────────────────┛初めまして!!この度は、どっぷりリファレン中をご購読いただきまして、本当に!本当に!ありがとうございますっ♪初回はいかがでしたでしょうか??感想&ご質問等ありましたらご遠慮なくお知らせいただけると、とても、とても、嬉しいですっ!!不定期の配信となりますが、次回の配信を首をながーくしてお待ちくださいね☆ by TI━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━<えす!エス!レスキュー SQL Server -どっぷりリファレン中!!->発行/編集:株式会社インサイトテクノロジーhttps://www.insight-tec.comwlmailhtml:{FFB7FEE3-FD66-4A13-AECC-755EBDF825BF}mid://00000000/!x-usc:mailto:letter\@insight-tec.co.jp本メールマガジンに掲載された記事を許可なく転載することを禁じます。Copyright(c) 2009, Insight Technology, Inc., All Rights Reserved.━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━※本メールマガジンは株式会社インサイトテクノロジーより許諾を受けて、紹介のために掲載しています。