#nofollow
#norelated
*はじめに [#e84c46c0]
WikiはCMSの一つで、誰でも(基本的に)全てのページを編集できるという割と無茶なシステムです。「新規」で新たにページを作り、「編集」ですでにあるページを編集します。整形ルールは「ヘルプ」にありますが、分かりづらいかもしれないので、簡易なチュートリアルをここに書いておきます。「ヘルプ」が分かりづらい場合に利用してください。このページを別ウィンドウ(別タブ)で開いて、実際に[[砂場]]や自分の名前で新規に作ったページを編集しつつ、適宜参照してください(手を動かさないと覚えない)。

Wikiの全てのルールを覚える必要はありません。このページでも細かい部分にはあまり触れず、よく使いそうな記法だけを説明します。最初は自分が使う記法のみを覚え、他の人の面白い書き方を見つけたら、そのページの編集画面を開いてソースを見たり、ヘルプを参照するなどして、必要な時に覚えていけばいいと思います。
*目次 [#t6658f9c]
&aname(contents);
#contents
--------------------------------------
*とりあえず書いてみる [#t1c235a2]
ただ文章をどべっと書くなら細かい知識は要りません。「新規」もしくは「編集」で現れる編集画面へ無心に打ち込み、「プレビュー」ボタンで表示を確認、「ページの更新」で結果を反映させてください。連続する複数の行は同じ段落と解釈され、空行を挟むと段落の切り替えになります。HTMLのタグは使えません。
*整形済みテキスト [#a3fe9364]
 整形済み〜ん   ←空白文字もそのまま反映〜ん
文章の行頭に半角スペースを書くと、整形済みテキスト(それ以上Wikiが整形しないテキスト)が書けます。ただどべっと書いた場合、半角スペースや改行が詰めて表示されますが、整形済みテキストではどちらも反映されるようになります。自分で改行しない限り折り返しがされないという事でもあるので、注意しないと文章がひどく横長になるかもしれません。複数行を整形済みにする場合、全ての行頭に半角スペースを置いてください。整形済みテキスト内ではWikiの記法によるその他の効果は適用されません。たとえば下の「[[リンクを作成>#make_link]]」で説明するブラケットも、整形済みテキスト内ではそのまま表示されます。
 [[ぶらけっとねーむ]]
HTMLでいうPREタグです。コピペの時に使うと楽です。
*リンクを作成 [#f825f381]
&aname(make_link);
Wiki内のページへのリンクを作るのは簡単です。ブラケット([[と]])でページ名を囲むと、そのページへのリンクになります。Wiki内に存在しないページ名をブラケットで囲むと「?」が表示され、そのページを新規作成するためのリンクになります。以下は
 [[いがらし]]
 [[存在しないページ]]
を書いた場合の例です。
-[[いがらし]]
-[[存在しないページ]]

* SQL Serverにおけるデータファイル・ページ・エクステント [#f6feee88]
ふざけて「存在しないページ」というページを作るとキレたいがらしにぶっ飛ばされます。注意してください。

** アジェンダ [#t092522b]
今回のメルマガでは以下の内容をお伝えします。
Wiki外へのリンクを作る場合、URLをそのまま書けばそのURLがリンクとして表示されます。URL以外の文字列をリンク名にしたい場合、[[適当な文字列:URL]]を使います。
 http://www.nagasakipu.ac.jp/
 [[カニカニ大学:http://www.nagasakipu.ac.jp/]]
-[[http://www.nagasakipu.ac.jp/]]
-[[カニカニ大学:http://www.nagasakipu.ac.jp/]]

+ データファイルとページ
+ データベースとデータファイル・ページ
-- ページの種類
-- ページとエクステントの関係
-- テーブルとページの関係
+ データファイルとエクステント
Wiki内のページへのリンクで、上の「カニカニ大学」のように別のリンク名を使いたい場合、[[リンク名>ページ名]]という書き方をします。
 [[コーラ魔人>いがらし]]
-[[コーラ魔人>いがらし]]

** データファイルとページ [#ib0168eb]
SQL ServerでもOracleでも、データはデータファイルに格納されていきます。そのデータファイルの中身はどうなっているんでしょうか?
「いがらし」のように、ページ名によってはブラケットを使わなくても、文中にページ名を書くだけでリンクになる場合がありますが、確実にリンクを作りたい場合はブラケットを使ってください。
*見出し [#c515853b]
行頭にアスタリスク「*」を置くと、見出しになります。「*」で大見出し、「**」で中見出し、「***」で小見出しと、3つのレベルに分けて使えます。このページの編集画面を開くと分かりますが、[[目次>#contents]]は手書きでページ内の見出しをリストしているのではなく、#contentsプラグインによってWikiにリストさせています。ページ内に見出しが増えれば目次の内容も自動的に増えますし、見出しの文が変われば目次の内容も自動で変わるので、ページのメンテナンスが楽になります。要点を見出しで目立たせるのは文章自体の読みやすさにもつながるので、効果的に利用してください。以下は
 **中見出し
 ***小見出し
 ****
と書いた場合の表示例です。
**中見出し [#y212070f]
***小見出し [#l0b363e9]
**** [#jf7a9e15]
↑レベルは3つまでなので、「*」を4つ並べても「小見出し+*」になる

まず最初に、接続中のインスタンスが使っているファイルの一覧を取得し、表示します。
#pre{{
<< SQL文 >>
/********************************************************************/
SELECT 
    *
FROM 
    sys.master_files;
/********************************************************************/
}}
sys.master_filesについては MSDNライブラリ参照。
[[http://msdn.microsoft.com/ja-jp/library/ms186782.aspx]]
*リストと表 [#y16663e3]
**箇条書き(リスト) [#c5262e9c]
***番号なし [#ga12a3a6]
行頭に「-」を置くと、箇条書きができます(順序なしリスト)。見出しと同様3つまでのレベルがあり、それぞれ「-」、「--」、「---」を使います。以下は順序なしリストの例です。
 -あんパン
 -食パン
 -カレーパン
 --ジャム
 --バター
 --チーズ
 ---だだんだん?
 ----
-あんパン
-食パン
-カレーパン
--ジャム
--バター
--チーズ
---だだんだん?
----
↑4つ続けるとリストではなく別の意味となる(行頭に「----」で水平線の表示)。
***番号付き [#sd6fd69a]
行頭に「+」で番号付きの箇条書きができます(順序付きリスト)。これも3つまでのレベルがあり、それぞれ「+」、「++」、「+++」を使います。以下は順序付きリストの例です。
 +ひとつ人世の生き血をすすり
 +ふたつ不埒な悪行三昧
 +みっつ見ないで汚れたおいらを
 ++よごれっちまったかなしみに
 ++きょうもこゆきの
 +++次なんだったか忘れた
 +++わすれっちまったかなしみに……(←ボケて誤魔化す)

#pre{{
<< 実行結果(抜粋) >>
/********************************************************************/
database_id file_id     type type_desc  name
----------- ----------- ---- ---------- ------------------------------
1           1           0    ROWS       master
1           2           1    LOG        mastlog
2           1           0    ROWS       tempdev
2           2           1    LOG        templog
3           1           0    ROWS       modeldev
3           2           1    LOG        modellog
4           1           0    ROWS       MSDBData
4           2           1    LOG        MSDBLog
5           1           0    ROWS       ReportServer
5           2           1    LOG        ReportServer_log
6           1           0    ROWS       ReportServerTempDB
6           2           1    LOG        ReportServerTempDB_log
7           1           0    ROWS       test
7           2           1    LOG        test_log
/********************************************************************/
}}
# 実行結果 http://www.insight-tec.com/mailmagazine/SQL_ref/sys.master_files.png
+ひとつ人世の生き血をすすり
+ふたつ不埒な悪行三昧
+みっつ見ないで汚れたおいらを
++よごれっちまったかなしみに
++きょうもこゆきの
+++次なんだったか忘れた
+++わすれっちまったかなしみに……(←ボケて誤魔化す)
***定義リスト [#jc7b07eb]
行頭に置いたコロン「:」と縦棒「|」でキーワードを挟み、続けて説明文を書くことで定義リストになります。
以下は
 :いがらし|チキン野郎
と書いた時の例です。
:いがらし|チキン野郎
**表 [#tba72a42]
「|」で文章を挟むと表が作れます。以下は
 |名前|客観的特徴|
 |いがらし|だめなひと|
 |KaNPa.|もっとだめなひと?|
の例です。
|名前|客観的特徴|
|いがらし|だめなひと|
|KaNPa.|もっとだめなひと?|
「|」のかわりにカンマ「,」を使っても同じことができます(CSV形式)。その場合行末のカンマは要りません。
*文の装飾 [#q71617ba]
**強調・斜体 [#w25faf33]
行中で文字列を2つのアポストロフィ「&#x27;&#x27;」で挟むと強調表示になります。3つのアポストロフィ「&#x27;&#x27;&#x27;」で挟むと斜体になります。
 ''強調表示''
 '''斜体'''
-''強調表示''
-'''斜体'''
**文字のサイズと色 [#hdda38d3]
行中で&#x26;size(文字サイズ){サイズを変える文字列};とすると文字のサイズを指定できます。文字サイズは半角数字で、ピクセル単位で指定します。最後のセミコロンまで忘れず書いてください。
 &size(20){20pxの文字列};
-&size(20){20pxの文字列};

行中で&#x26;color(文字色、背景色){色を変える文字列};とすると&color(green){文字};と&color(white,red){背景};の色を指定できます。背景色は省略できます。色の指定は「色キーワード」「#16進数3桁(RGB)」「#16進数6桁(RRGGBB)」の3つの方法が使えます。最後のセミコロンまで忘れず書いてください。
 &color(blue){青い血の少年};
 &color(white,green){くりーむそーだ};
 &color(#00f){あーおいちの少年};
 &color(#ffffff,#00ff00){くりーむそーだ};
 &color(#ffffff,#00ff00){&size(20){でっかいくりーむそーだ};};
 &color(black){セミコロンが足りない、片手落ち}
-&color(blue){青い血の少年};
-&color(white,green){くりーむそーだ};
-&color(#00f){あーおいちの少年};
-&color(#ffffff,#00ff00){くりーむそーだ};
-&color(#ffffff,#00ff00){&size(20){でっかいくりーむそーだ};};
-&color(black){セミコロンが足りない、片手落ち}

*その他 [#v239b78c]
**プラグイン [#u818572c]
既に述べた#contentsのように、PukiWikiはプラグインと呼ばれる便利な機能を持っています。文字の色、サイズを変える&sizeや&colorも実はプラグインの一つです。プラグインの一覧や詳しい使い方は[[プラグインマニュアル>PukiWiki/1.4/Manual/Plugin]]にありますが、一応ここでよく使うプラグインの名前を幾つか挙げておきます。
,#aname(&aname),アンカーの作成
,#contents,見出しを解析して目次を自動生成
,#comment,一言コメント用のフォームを設置
,#vote,投票フォームの設置
,#ls(ls2),階層化されたページ((「既存のページ名/新規ページ名」という風にスラッシュで区切ってページを新規作成すると、指定した既存のページを親とする階層化されたページが作れる))の一覧表示
**インライン要素とブロック要素 [#gec99976]
PukiWikiの文字列や段落、リスト、表、といった各要素には、インライン要素とブロック要素という区別があります。ブロック要素の中にインライン要素を書くことは出来ますが、インライン要素の中にブロック要素を書くことはできません。ブロック要素を別のブロック要素の中に書くことは、出来る場合と出来ない場合があります。

この結果を見て分るように、
-- 行データが入るファイル
-- ログデータが入るファイル
の2種類のファイルが存在していることが分るかと思います。
例えば文字列は全てインライン要素であり、&size()や&color()の結果も、ブラケットで囲んだリンクもインライン要素です。これらはリストや表、見出しなどの、ブロック要素の中に書くことができます。親(中に書かれる方)と子(中に入る方)のどちらもブロック要素である場合、たとえばリストの中に表を入れる、ということはできますが、表の中にリストを入れるとか、見出しの中に表を入れるということはできません。詳細な情報はヘルプの整形ルールに載っています。

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に対応するデータベースの名前が表示されるようにしました。
[[http://msdn.microsoft.com/ja-jp/library/ms189753.aspx]]

それでは、組みあがったSQL文と実行結果を記載します。
#pre{{
<< 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
;
/********************************************************************/
}}
#pre{{
<< 実行結果(抜粋) >>
/********************************************************************/

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)
 
/********************************************************************/
}}
# 実行結果
[[http://www.insight-tec.com/mailmagazine/SQL_ref/sys.master_files_change1.png>sys.master_files_change1.png]]


ここから、結果の中にある1つのファイルをピックアップして情報を見ていきます。

1行目にあるmasterというデータベースのsizeには"512"と出力されています。しかし、physical_nameで指定されているファイルのプロパティをみると、実際のファイルサイズは4,194,304 バイトです。
[[http://www.insight-tec.com/mailmagazine/SQL_ref/master.mdf.png>master_mdf.png]]

では、SQLの結果で出力された"512"は何を示しているのでしょうか?

sys.master_filesの説明を見ると"size列は、現在のファイル サイズ (8 KB ページ単位) "とあります。
よってこの512は、「8KBのページ数が512個はいっています。」といっているわけです。

試しに、先ほどのsize部分がバイトで出力されるように修正します。

#pre{{
<< 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
;
/********************************************************************/
}}
#pre{{
<< 実行結果(抜粋) >>
/********************************************************************/
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)
/********************************************************************/
}}
[[http://www.insight-tec.com/mailmagazine/SQL_ref/sys.master_files_change2.png>sys.master_files_change2.png]]


これで、ファイルのプロパティで表示されていたファイルサイズとSQL出力結果のsizeが一致し、SQL Serverのページが8KBである事を実感できたかと思います。

** データベースとデータファイル・ページ [#ue82a5af]
先ほどまでの検証にて、データファイルの中には"ページ"というものが存在している事を感じていただけたかと思います。
今度はそのページとは何かをみていきます。

事前準備として、使用するデータベースとテーブルを作成します。
#pre{{
<< SQL文 >>
/********************************************************************/
USE [master]
GO

CREATE 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' 
)

Go
USE [mini]
GO
CREATE 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です。
#pre{{
<< SQL文 >>
/********************************************************************/
USE [mini]
GO

SELECT
    *
FROM
    sys.data_spaces;
/********************************************************************/
}}
[[http://msdn.microsoft.com/ja-jp/library/ms190289.aspx]]

#pre{{
<< 実行結果 >>
/********************************************************************/
name    data_space_id type type_desc      is_default
------- ------------- ---- -------------- ----------
PRIMARY 1             FG   ROWS_FILEGROUP 0
miniSec 2             FG   ROWS_FILEGROUP 1
/********************************************************************/
}}
この結果により、CREATE DATABASEのON以下で指定した"PRIMARY"というファイルグループと"miniSec"というファイルグループが表示されます。

次に、このデータベースのアロケーションユニットの一覧を取得してみます。
アロケーションユニットについてはMSDNライブラリ参照[[http://msdn.microsoft.com/ja-jp/library/ms189051.aspx]]

#pre{{
<< SQL文 >>
/********************************************************************/
USE [mini]
GO

SELECT
    *
FROM
    sys.allocation_units
;
/********************************************************************/
}}
[[http://msdn.microsoft.com/ja-jp/library/ms189792.aspx]]

#pre{{
<< 実行結果(抜粋) >>
/********************************************************************/
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を改変し、実行します。

#pre{{
<< SQL文 >>
/********************************************************************/
USE [mini]
GO

SELECT 
    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.rows
FROM 
    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_id
ORDER BY object_id
;
/********************************************************************/
}}
#pre{{
<< 実行結果(抜粋) >>
/********************************************************************/
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        0
0          2105058535  tb1         1        0
0          2105058535  tb1         1        0
/********************************************************************/
}}

これでどのオブジェクトが、どれぐらいの行数があり、どれぐらいページを使用しているかが分るようになりました。
さらに突っ込んで、これをファイル/ファイルグループと繋げてみます。

#pre{{
<< SQL文 >>
/********************************************************************/
USE [mini]
GO

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.rows
FROM 
    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_id
ORDER BY object_id
;
/********************************************************************/
}}
#pre{{
<< 実行結果(抜粋) >>
/********************************************************************/
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        0
2105058535  tb1         1        0
2105058535  tb1         1        0
/********************************************************************/
}}

これで、ファイル/ファイルグループに格納されているページ数がいくつか、格納されているオブジェクトが何で、どれぐらいの行数あるのかが見えるようになりました。

ここでテーブルに1行データをいれて、先ほどのSQLを再度実行してみたいと思います。
#pre{{
<< SQL文 >>
/********************************************************************/
insert into tb1 values ( 1, null, null, null);
/********************************************************************/
}}
#pre{{
<< 実行結果(抜粋) >>
/********************************************************************/
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          1
72057594039894016  ROW_OVERFLOW_DATA 0           0          0
72057594039959552  LOB_DATA          0           0          0

object_id   object_desc index_id rows
----------- ----------- -------- ----
2105058535  tb1         1        1
2105058535  tb1         1        1
2105058535  tb1         1        1
/********************************************************************/
}}

データを1行追加した事で、tb1のIN_ROW_DATAが使用しているページの数が2に増えました。
行データで1ページ、nvarcharが格納されるページで1ページ使用しているので、計2ページの使用になります。

さらに、1行追加して再実行します。
#pre{{
<< SQL文 >>
/********************************************************************/
insert into tb1 values ( 2, null, null, null);
/********************************************************************/
}}
#pre{{
<< 実行結果(抜粋) >>
/********************************************************************/
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          1
72057594039894016  ROW_OVERFLOW_DATA 0           0          0
72057594039959552  LOB_DATA          0           0          0

object_id   object_desc index_id rows
----------- ----------- -------- ----
2105058535  tb1         1        2
2105058535  tb1         1        2
2105058535  tb1         1        2
/********************************************************************/
}}
今度は格納行数が2行に増えましたが、使用ページ数は増えていません。よって、1ページには複数行のデータが格納されていることが分ります。

次に、tb1.col1に大きいバイト数のデータをUpdateをして、再実行します。
#pre{{
<< SQL文 >>
/********************************************************************/
USE [mini]
GO

UPDATE tb1 
SET col1 = REPLICATE(N'〜', 4000)
;

GO

SELECT
    DATALENGTH(col1) col1_len 
FROM 
    tb1
WHERE
    id = 1
; 
    
USE [mini]
GO
SELECT
    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.rows
FROM 
    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_id
ORDER BY data_space_id
;
/********************************************************************/
}}
#pre{{
<< 実行結果(抜粋) >>
/********************************************************************/
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          2
72057594039894016  ROW_OVERFLOW_DATA 0           0          0
72057594039959552  LOB_DATA          0           0          0

object_id   object_desc index_id rows
----------- ----------- -------- ----
2105058535  tb1         1        2
2105058535  tb1         1        2
2105058535  tb1         1        2
/********************************************************************/
}}

今度はtb1.col1のバイト数8,000バイト×2になったので、1ページ(8KB)に格納きしれず、tb1のIN_ROW_DATAが使用しているページ数が増えました。

同様にtb1.col2に大きいバイト数のデータをUpdateをして、再実行します。
#pre{{
<< SQL文 >>
/********************************************************************/
UPDATE tb1 
SET col2 = REPLICATE(N'〜', 4000)
;

USE [mini]
GO
SELECT
    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.rows
FROM 
    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_id
ORDER BY data_space_id
;
/********************************************************************/
}}
#pre{{
<< 実行結果(抜粋) >>
/********************************************************************/
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          2
72057594039894016  ROW_OVERFLOW_DATA  0           0          0
72057594039959552  LOB_DATA           3           3          0

object_id   object_desc index_id rows
----------- ----------- -------- ----
2105058535  tb1         1        2
2105058535  tb1         1        2
2105058535  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すると、結果が以下のようになります。
#pre{{
<< 実行結果(抜粋) >>
/********************************************************************/
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          2
72057594039894016  ROW_OVERFLOW_DATA 3           3          0
72057594039959552  LOB_DATA          5           5          0

object_id   object_desc index_id rows
----------- ----------- -------- ----
2105058535  tb1         1        2
2105058535  tb1         1        2
2105058535  tb1         1        2
/********************************************************************/
}}

この様に、ページには複数行格納されているものもあれば、複数ページで1つのデータを格納しているものもあります。
このあたりの詳細はMSDNを参照すると、より理解できるかと思います。
ページとエクステントについて 
MSDN [[http://msdn.microsoft.com/ja-jp/library/ms190969.aspx]]
参照:8 KB を超える場合の行オーバーフロー データ
MSDN [[http://msdn.microsoft.com/ja-jp/library/ms186981.aspx]]

** データファイルとエクステント [#pf502a23]
ここで話を最初のデータファイルの方に戻します。このminiというデータベースを作成し、tb1というテーブルを作成、レコード2件登録、col1, col2, col3とUpdateしてきました。
ここまでの状態で、mini.dbo.tb1がデータを格納するために使用しているファイルのサイズは524,288 バイトになっていました。

この状態から、データをこのままで1件ずつ増やしていきたいと思います。
#pre{{
<< SQL文 >>
/********************************************************************/
INSERT INTO
    tb1
SELECT 
    id + 1, 
    col1, 
    col2, 
    col3 
FROM
    tb1 
WHERE
    id = ( SELECT MAX(id) FROM tb1 )
;
/********************************************************************/
}}

このSQLを何度も発行し、最初にデータの増減があった17行目でデータファイルのサイズやデータベースのページ数を取得してみます。
#pre{{
<< 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.rows
FROM 
    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_id
ORDER 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
;
/********************************************************************/
}}
#pre{{
<< 実行結果(抜粋) >>
/********************************************************************/
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          2
72057594039894016  ROW_OVERFLOW_DATA 25          18         0
72057594039959552  LOB_DATA          41          35         0

object_id   object_desc index_id rows
----------- ----------- -------- ----
2105058535  tb1         1        17
2105058535  tb1         1        17
2105058535  tb1         1        17

======================================================================

dbname physical_name                size    max_size growth
------ ---------------------------- ------- -------- ----------
mini   C:\SQL ServerData\miniSec.mdf 655360  無制限  8page(s)
/********************************************************************/
}}

ファイルサイズが524288バイトから655360バイトへ増加しました。これによって
--増加したページ数は128ページ
--増加したエクステント数は16エクステント
だと分ります。
#pre{{
(655360 - 524288)/8192 = 16ページ
16 / 8 = 2 エクステント
}}

次はINSERTのデータを少なくして、増加をみてみます。
#pre{{
<< SQL文 >>
/********************************************************************/
INSERT INTO
    tb1
SELECT 
    id + 1, 
    col1,
    null,
    null
FROM
    tb1 
WHERE
    id = ( SELECT MAX(id) FROM tb1 )
;
/********************************************************************/
}}
このSQLを何度も発行し、最初にデータの増減があった状態は以下のようになります。
#pre{{
<< 実行結果(抜粋) >>
/********************************************************************/
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       7           7          5
72057594039894016  ROW_OVERFLOW_DATA 25          18         0
72057594039959552  LOB_DATA          41          35         0

object_id   object_desc index_id rows
----------- ----------- -------- ----
2105058535  tb1         1        20
2105058535  tb1         1        20
2105058535  tb1         1        20

dbname physical_name                size    max_size growth
------ ---------------------------- ------- -------- ----------
mini   C:\SQL ServerData\miniSec.mdf 720896  無制限   8page(s)

/********************************************************************/
}}

ファイルサイズが655360バイトから720896バイトへ増加しました。
--これによって増加したページ数は8ページ
--増加したエクステント数は1エクステント
だと分ります。

これまでの、データ増加は1ページより大きいデータを追加してきました。では、1ページ未満のデータを数件いれて増加量を見てみようと思います。
#pre{{
<< SQL文 >>
/********************************************************************/
INSERT INTO
    tb1
SELECT 
    ( SELECT MAX(id) FROM tb1 ) + 1, 
    REPLICATE(N'0',1000),
    null,
    null
;
/********************************************************************/
}}
このSQLを何度も発行し、最初にデータの増減があった状態は以下のようになります。
#pre{{
<< 実行結果(抜粋) >>
/********************************************************************/
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       17          10         8
72057594039894016  ROW_OVERFLOW_DATA 25          18         0
72057594039959552  LOB_DATA          41          35         0

object_id   object_desc index_id rows
----------- ----------- -------- ----
2105058535  tb1         1        29
2105058535  tb1         1        29
2105058535  tb1         1        29

dbname 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ページ単位になります。

** まとめ と 考察 [#gf01df35]
- データベースにはデータが格納されるデータファイルと、ログが格納されるログファイルとを持っている。
これによって、SQL Serverはデータベースごとにログファイルを持つ構造になっていることがわかる。よって、インスタンス毎ではなく、データベース毎のバックアップ & 復旧が行われる必要がある。
-データベースはページという単位を持っていてページはデータファイルの中に書きこまれる最小単位である。
また、ページにはテーブルのデータが格納されていて、1ページに複数行格納されている。ただし、8KBを超えるデータの場合、ページをまたがってデータが格納される。
1ページは8KBという制限があるので、列長を8KBよりも大きくするときは、性能面での考慮が必要。(ページ毎にバッファへのデータ入出力が行われるため)
- データが格納できるページが無くなると、ファイルの拡張が発生する。
また、データファイルは最小64KB単位で増えていく。よって、8ページ=1エクステント単位で増えていく。
SQL Serverのデータファイルを格納するディスクがデータ増加により、知らない間に圧迫されないか気を払う必要がある。特に、無制限拡張をしている場合は使えるだけどんどんファイルサイズが増加するので注意が必要。
- データファイルには、ファイルとグループの2種類がある。
ファイルグループを使い、実ファイルを複数ディスクに分散させることが出来る。

インライン要素とブロック要素、親要素と子要素、といった関係は一見複雑なようですが、慣れてくると直感的に理解できるようになります。HTMLやCSSの経験があるとより分かりやすいかもしれません。
**FAQ [#mcac20f2]
:ページを削除したい!|編集画面で全ての内容を削除し、「ページの更新」ボタンを押すと削除になります。
:メニューバーの内容を変えたいんだけど?|MenuBarのページを編集してください。
:俺のページだけ別のメニューバーを表示させたい!|#includesubmenuというプラグインがあります。
**書き方以外 [#u2415269]
「ページの変更点」や「バックアップ」と現在との差分を見ると、自分が見てない間にどこが変わったのかが分かります。

トップ   編集 ページの変更点 バックアップ 添付 複製 名前変更 リロード   新規 ページ一覧 単語検索 最近更新されたページ   ヘルプ   最終更新のRSS