SQL Server は内部で SQL Server 独自のスケジューラーとして SQLOS (または User Mode Scheduler) が起動しています。
通常、SQLOS のスケジューラーは各コアに対して起動しており、4 コア CPU の場合は以下のようになります。
# sys.dm_os_schedulers から取得可能です。
![]()
VISIBLE ONLINE となっているのがユーザーセッションで使用可能なスケジューラーとなり、この環境では 0 ~ 3 までの 4 個のスケジューラーを使用することが可能です。
# (DAC) となっているのは専用管理者接続用なので数に含めていません。
スケジューラーが複数あるということは複数コアが SQL Server に割り当てられているので、複雑な処理のクエリを実行する際に複数の CPU を使用した並列クエリ (Pararell Query) が使用できるようになります。
![]()
裏ワザで特殊なスタートアップオプションを使うと物理コア数以上のスケジューラーを起動することができたりもします。
# 下の画像は 1 コアの CPU の環境で 16 個のスケジューラーを起動した例になります。
![]()
SQL Server からは有効な CPU として認識しているので、1 CPU 環境でも並列クエリが実行できたりします。
![]()
![]()
このあたりが SQL Azure ではどのようになっているかを確認してみようというのが今回のお話です。
Contents
■スケジューラー数を確認
まず、手始めとして SQL Azure ではスケジューラーがいくつ起動しているかを確認してみたいと思います。
今回は Web エディションの 1GB の DB 環境を使用してテストをしています。
SQL Azure では、[sys.dm_os_schedulers] [sys.dm_os_sysinfo] といった DMV を使用することができません。
そのため単純な方法ではスケジューラーの数を確認することができません。
では、どうすればよいかというと [sys.dm_exec_requests] の [scheduler_id] 列を使用します。
この列から実行中の要求がどのスケジューラーに割り当てられているかを確認することができます。
複数の要求を同時に実行して、各要求がどのスケジューラーに割り当てらえているかを取得することで、対象の SQL Azure のサーバー上でスケジューラーがいくつ起動しているかを確認することができます。
今回は 300 接続で SQL Azure に対してクエリを実行してみました。
その時の [sys.dm_exec_requests] の状態がこちらになります。
![]()
0 ~ 7 まで 8 個のスケジューラーが起動していることが確認できます。
同様のクエリをスケジューラーを 8 個用意したオンプレミスの SQL Server に対して実行してみます。
![]()
内部使用のスケジューラーの情報も見えてしまいますが、ユーザーが使用できるスケジューラーは 0 から 7 までなので先ほど SQL Azure に対して実行した結果とほぼ同じ内容が取得できていますね。
ここから、SQL Azure では?8 個のスケジューラーが用意されていることが確認できます。
実際に CPU コアとして割り当てられているのか、それともオンプレミスの SQL Server でもできるように擬似的に複数のスケジューラーを用意しているのかまではここからは読み取れませんが…。
■並列クエリは実行できる?
SQL Azure では実際の CPU の物理コア数との関係まではわかりませんが複数のスケジューラーが用意されていることが確認できました。
次に複数の CPU を使用した並列クエリが実行できるかを確認してみたいと思います。
今回、オンプレミスの SQL Server と SQL Azure で同じ特性を持つデータを準備してみました。
テーブルの定義としては以下のようになります。
| CREATE TABLE [dbo].[Table_1]( ??? [Col1] [int] IDENTITY(1,1) NOT NULL, ??? [Col2] [char](4000) NULL, CONSTRAINT [PK_Table_1] PRIMARY KEY CLUSTERED ([Col1] ASC) ) |
このテーブルに対して以下のクエリでデータを挿入します。
| DECLARE @i int = 0 WHILE (@i < 20000) BEGIN ??? INSERT INTO Table_1(Col2) VALUES(NEWID()) ??? SET @i += 1 END |
このテーブルで並列クエリを実行するために以下のような SELECT を実行してみます。
| SELECT COUNT(*) FROM Table_1 GROUP BY Col2 |
オンプレミスの SQL Server で実行プランを確認してみると以下のように並列クエリとして実行されていることが確認できます。
![]()
それでは同様のクエリを SQL Azure で実行してみます。
![]()
SQL Azure でも複数のスケジューラーが起動しているのは確認ができていますが、並列クエリとしては実行されていないですね。
| SELECT COUNT(*) FROM Table_1 GROUP BY Col2 OPTION (MAXDOP 8 ) |
のように MAXDOP を指定しても実行プランは変わりません。
この動作に関しては以下の技術文書に記載がされています。
Supported Transact-SQL Statements (SQL Azure Database)
SQL Azure Database always sets the max degree of parallelism to
1automatically and ignores the MAXDOP hint even if it is used. In addition
SQL Azure では、[max degree of parallelism] が [1] で設定され、 MAXDOP のヒントを指定しても無視されるため、
並列クエリは実行されないようです。
オンプレミスの SQL Server のデフォルトの設定では [max degree of parallelism] は [0] (使用可能な CPU をすべて使う) 設定となっています。
そのため、MAXDOP のヒントを指定しないでも複数の CPU を使用したほうが効率が良いとオプティマイザが判断した場合は並列クエリとして実行されます。
オンプレミスの SQL Server で MAXDOP のヒントを無視するという設定はできないと思うのですが、[max degree of parallelism] の設定を SQL Azure と同様に [1] に設定するのであれば以下のクエリで設定可能です。
| EXEC sp_configure ‘show advanced options’, 1 RECONFIGURE EXEC sp_configure ‘max degree of parallelism’,1 RECONFIGURE EXEC sp_configure ‘max degree of parallelism’ |
[max degree of parallelism] の設定後に並列クエリとして実行されていたクエリを再度実行してみます。
![]()
[max degree of parallelism]? は [1] となっていますので、MAXDOP ヒントを使用しない場合は、並列クエリとしては実行されなくなります。
MAXDOP ヒントを使用するとこのように並列クエリとして実行されます。
![]()
SQL Azure では並列クエリとして実行されないことを考えると開発用のオンプレミスの環境は [max degree of parallelism] を [1] にしておくと、実行プランを近くすることができて良いかもしれないですね。
[…] 以前、SQL Azure のスケジューラー数と並列クエリについて という投稿をしました。 スケジューラー系で SQL Azure の NUMA ノード数がどうなっているのかが気になったので調べてみました。 […]
SQL Azure の NUMA ノード数を想像してみる « SE の雑記
15 6月 11 at 23:35