都内で働くSEの技術的なひとりごと / Technical soliloquy of System Engineer working in Tokyo

都内でサラリーマンやってます。SQL Server を中心とした (2023年からは Azure も。) マイクロソフト系(たまに、OSS系などマイクロソフト以外の技術も...)の技術的なことについて書いています。日々の仕事の中で、気になったことを技術要素関係なく気まぐれに選んでいるので記事内容は開発言語、インフラ等ばらばらです。なお、当ブログで発信、発言は私個人のものであり、所属する組織、企業、団体等とは何のかかわりもございません。ブログの内容もきちんと検証して使用してください。英語の勉強のため、英語の

SQL Server Management Studio の知っておいたほうが良い機能について挙げてみる - その14 - ( SSMS 18 の新しい機能 )

 さて、10 連休のゴールデンウィークが始まりました。しかも、連休中に平成から令和に変わるという歴史的なゴールデンウィークです。最近、SQL Server の CTP のアップデートが早いなぁと思っていたら、SSMS の 18 が GA されました。SQL Server 関連で新しいバージョンが出たときはどうしても、dmv、実行プラン周りなどに目がいきがちです。SSMS のグラフィカルな実行プランで変更があったので、早速試してみました。
※AdventureWorks2017, SalesOrderHeader を使用しています。
※OrderDate の非クラスタ化インデックスを作成しています。

 下記のクエリを SQL Server Management Studio で実行してみましょう。

SELECT
    SalesOrderID,
    RevisionNumber,
    OrderDate,
    DueDate,
    ShipDate,
    Status,
    OnlineOrderFlag,
    SalesOrderNumber,
    PurchaseOrderNumber,
    AccountNumber,
    CustomerID,
    SalesPersonID,
    TerritoryID,
    BillToAddressID,
    ShipToAddressID,
    ShipMethodID,
    CreditCardID,
    CreditCardApprovalCode,
    CurrencyRateID,
    SubTotal,
    TaxAmt,
    Freight,
    TotalDue,
    Comment,
    rowguid,
    ModifiedDate
FROM
    AdventureWorks2017.Sales.SalesOrderHeader WITH(INDEX(NonClusteredIndex))
WHERE
    OrderDate BETWEEN '2011-05-30 00:00:00.000' AND '2012-05-31 00:00:00.000'

f:id:koogucc11:20190427181744p:plain
実行結果

 よく見ると見慣れないものがオペレータに表示されています。

f:id:koogucc11:20190427182111p:plain
オペレーターに新たな何かが表示されている!?

 オペレーター単位の経過時間、実際の行数および推定の行数が表示されています。これはいいですね。パッとみて統計の問題が発生していないかなど判断することが可能です。赤線の引かれている 3028 が実際の行、青線の引かれている 3041 が推定の行数です。

f:id:koogucc11:20190427182532p:plain
実際の行数と推定の行数

 バージョンアップされるたびに、いい改善が追加されていますね。有難いです。

 こんな SQL Server 本あるのか。ちょっと見てみたい。

 こんな感じのキャンプで使えるチェア欲しい。

 

SQL Server の構造について記事にしてみる - その4 ( SQL Server 2019 をインストールしたら、sys.dm_db_page_info というものを見つけたのでちょっと動きをしらべてみた ) -

 少しだけ SQL Server 2019 をお触りしてみました。その中で一つ気になった sys.dm_db_page_info (Transact-SQL) - SQL Server | Microsoft Docs というものがあり、もしや DBCC PAGE の代替となるものでは!と思い調べてみました。

 DBCC PAGE といえば、『 SQL Server の構造について記事にしてみる 』 でインデックスの構造を調査するのに使用していました。
ryuchan.hatenablog.com

 その後、図とか色々と書くのが面倒なため、シリーズはその3で打ち切りとなっていました(笑) 今回はちょっと興味を持ったので、勢いにまかせて一気に記事書きます。
※『 SQL Server の構造について記事にしてみる - その3 』で使用したクエリをベースにします。
※ データベースは、AdventureWorks2017 を使っています。
※テーブルは、Sales.SalesOrderHeader を使っています。

 それでは、早速下記のクエリを SQL Server Management Studio で実行してみましょう。

SELECT
    dpa.allocated_page_page_id,
    dpa.page_type,
    dpa.page_type_desc,
    dpa.page_level,
    dpa.next_page_page_id,
    dpa.previous_page_page_id
FROM
    sys.dm_db_database_page_allocations(DB_ID(), OBJECT_ID('Sales.SalesOrderHeader'), null, NULL, 'DETAILED') dpa

f:id:koogucc11:20190421113513p:plain
クエリの結果

 次に、下記のクエリを SQL Server Management Studio で実行してみましょう。

DBCC TRACEON(3604)
DBCC PAGE(N'AdventureWorks2017',1,16416,3) WITH TABLERESULTS
DBCC TRACEOFF(3604)

f:id:koogucc11:20190421113826p:plain
DBCC PAGE の結果

 次に、dm_page_info を使ったクエリを SQL Server Management Studio で実行してみましょう。

SELECT
    pi.*
FROM
    sys.dm_db_database_page_allocations(DB_ID(), OBJECT_ID('Sales.SalesOrderHeader'), null, NULL, 'DETAILED') dpa 
CROSS APPLY 
    sys.dm_db_page_info(dpa.database_id, dpa.allocated_page_file_id, dpa.allocated_page_page_id, 'DETAILED') pi
WHERE
    dpa.allocated_page_page_id = 16416

f:id:koogucc11:20190421114418p:plain
f:id:koogucc11:20190421114435p:plain
f:id:koogucc11:20190421114447p:plain

f:id:koogucc11:20190421114457p:plain
dm_page_info の結果

 DBCC PAGE のヘッダー情報にあたるものくらいが取得できるようです。Undocumented な DBCC コマンドが dmv 化されたか!?と思ったのですが、DBCC PAGE の全ての情報を参照できるものでは無いようです。バージョンアップされることで、データ部、個別情報を出力できる dmv が追加( dm_page_info_detail... とか? )されるのでしょうか。今後のバージョンアップに期待ですね。

最新の iPad mini が欲しい。

Apple iPad mini 4 (Wi-Fi, 128GB) - シルバー (第4世代)

Apple iPad mini 4 (Wi-Fi, 128GB) - シルバー (第4世代)

けど、iPad Pro 11 に使える Pencil も欲しい。
www.amazon.co.jp

SQL Server Management Studio の知っておいたほうが良い機能について挙げてみる - その13 - ( オブジェクトエクスプローラーの詳細って? )

 お久しぶりです。もう半年ほど記事投稿していませんでした。そして、二カ月ほど SQL Server を扱っていませんでした。時間もあったんですが、仕事で使わないものは中々使う気にならないですし、記事にしようという気力が湧かないものです。今日久しぶりに Windows Update をしようかと思い、Parallels から Windows を起動してみました。そして、ついでに SQL Server Management Studio を 17.9.1 へアップデートしてみました。
 

f:id:koogucc11:20190416002014p:plain
懐かしの SSMS 笑

 メニューを触っていると、表示→オブジェクトエクスプローラーの詳細というメニューを見つけました。クリックしたこともなかったので、クリックしてみます。ふむ、選択したオブジェクトの詳細が参照できるわけですね。

f:id:koogucc11:20190416002707p:plain
オブジェクトエクスプローラーの詳細でデータベースを選択

 さらにクリックして行くと、テーブルのプロパティも参照できます。

f:id:koogucc11:20190416003014p:plain
オブジェクトエクスプローラーの詳細でテーブルを選択

 列を右クリックすると、一覧に表示する列をカスタマイズできます。

f:id:koogucc11:20190416003219p:plain
オブジェクトエクスプローラーの詳細の列で右クリック

 うーん。dmv 使ってクエリ書くかな笑。久しぶりの投稿内容が薄っぺらくて申し訳ありませんでした。

 少し前に第三世代の iPad Pro 買ったから、Apple Pencil 2 も欲しいなぁ。

Apple Pencil(第2世代)

Apple Pencil(第2世代)

 Apple Watch 4 のベルトを新調。純正は高いので、お安いものを購入。

やはりダークテーマはいいなぁと思って SSMS ver. 18 Preview 4 を扱っていたら、Azure Data Studio とか見えたのでお試してみた

 SQL Server Management Studio 18 preview 4 がリリースされました。
cloudblogs.microsoft.com

 やっぱりダークテーマはいいですね。可能であれば、オブジェクトエクスプローラーも Visual Studio と同じくダークなテーマになるとより見やすくなるかなと思います。(おそらく正式リリースでは対応されるんでしょう。)
f:id:koogucc11:20181007225018p:plain

 明るい箇所があると目に優しくないですね。
f:id:koogucc11:20181007225428p:plain

 mac も速攻ダークに変えました。たまに対応していないツールがあったりすると、目が疲れますが....

 ちょっとメニューを触っていたら、見慣れない ( というか自分が情弱なだけ? ) 項目が目に入ってきました。Azure Data Studio。
f:id:koogucc11:20181007225609p:plain

 インストールしてみました。あれ、SQL Operations Studio じゃない?名前が変更されたんですかね?
f:id:koogucc11:20181007230751p:plain

 色々リリースされていますね。もうまったくついていけていません。SQL Server については情弱の一途をたどっています...

 これくらいのバッテリーがほしくなってきました。キャンプ兼災害時用。色々あって迷ってしまいます。やはり信頼性の高い Anker ですかね?

 ソーラーパネルもあると対策としては完璧かもしれませんね。

実行プランの読み方をまとめてみる - その11 ( Where 句の条件の型が列の型と異なる場合の実行プランを読んでみる ) -

 実行プランの読み方は情報も少ないので、内容の理解に苦しんでいる方も多いかもしれません。過去にはいくつか投稿しているので、そちらも参考にしてください。
ryuchan.hatenablog.com
ryuchan.hatenablog.com
ryuchan.hatenablog.com
ryuchan.hatenablog.com
ryuchan.hatenablog.com
ryuchan.hatenablog.com
ryuchan.hatenablog.com
ryuchan.hatenablog.com
ryuchan.hatenablog.com
ryuchan.hatenablog.com

 さて、過去の投稿を参考にしつつ、今回投稿する記事も参考にして、実行プランをスラスラ読めるようにしましょう。早速下記のクエリを実行して見ましょう。
※データベースは、ここからダウンロードしてください。
※クエリはわざと不適切な状態にしています。

-- OrderDate 型は datetime なので型が間違っている。
DECLARE @min_date datetime2
DECLARE @max_date datetime2

SET @min_date = '2011-05-31 00:00:00.000'
SET @max_date = '2011-07-31 00:00:00.000'

SET STATISTICS PROFILE ON

SELECT 
    SalesOrderID,
    RevisionNumber,
    OrderDate
FROM 
    -- OrderDate のインデックスを作成した。
    Sales.SalesOrderHeader WITH (INDEX(IX_SalesOrderHeader_OrderDate))
WHERE 
    OrderDate > @min_date
AND OrderDate < @max_date

SET STATISTICS PROFILE OFF

 実行プランは下図の通りです。
f:id:koogucc11:20180819234905p:plain

 Computer Scalar、Concatenation, Merge Interval オペレータって何しているかはっきりわかりませんよね?それぞれのオペレーターのプロパティを見ても、定義済みの値が [Expr1008] = (Expr1003, Expr1006), [Expr1009] = (Expr1004, Expr1007), [Expr1010] = (Expr1002, Expr1005) とか、出力一覧がExpr1003, Expr1004, Expr1002とか意味不明ですね。expr といえば、整数計算とか式評価を思い浮かべますが....

  • Compute Scalar
    f:id:koogucc11:20180819235900p:plain

  • Concatenation
    f:id:koogucc11:20180819235903p:plain

  • Merge Interval
    f:id:koogucc11:20180819235906p:plain

 さて、今回のような実行プランを見ていくにはグラフィカルな実行プランでは詳細はわかりません。各オペレーターの詳細情報を参照するには、実行プランの XML を参照するか、SET STATISTICS PROFILE ON の結果を参照する必要があります。今回は、SET STATISTICS PROFILE ON の結果を見ていくことにしましょう。今回実行したクエリには、SET STATISTICS PROFILE ON を付加してあるので、下図の赤枠の情報も出力されているかと思います。赤枠部分の情報を詳しく見ていきましょう。
f:id:koogucc11:20180820001109p:plain

 まず、Compute Scalar オペレーターの内容から参照してみましょう。GetRangeWithMismatchedTypes という関数が発生しています。文字通り型指定が間違っているけど、範囲を取得するみたいな関数(あっているかはわかりません。)ですね。下記のパターンでは、Expr1003 = @min_date, Expr1004 = NULL がそれぞれ割り当てられます。
※(6)が何に使用されるのかイマイチ推測できない…

([Expr1003],[Expr1004],[Expr1002])=GetRangeWithMismatchedTypes([@min_date],NULL,(6))

 下記のパターンでは、Expr1006 = NULL , Expr1007 = @max_date がそれぞれ割り当てられます。

([Expr1006],[Expr1007],[Expr1005])=GetRangeWithMismatchedTypes(NULL,[@max_date],(10))

 上記の結果をクエリに当てはめると下記のようになります。

SELECT
    SalesOrderID,
    RevisionNumber,
    OrderDate
FROM
    Sales.SalesOrderHeader WITH(INDEX(IX_SalesOrderHeader_OrderDate))
WHERE
    (
        OrderDate > Expr1003
    AND OrderDate < Expr1004
    )
AND (
        OrderDate < Expr1007
    AND OrderDate > Expr1006
    )

 次に、Concatenation オペレーターをみていきましょう。 OrderDate > Expr1003 と OrderDate > Expr1006、OrderDate < Expr1004 と OrderDate < Expr1007 が結合されます。

[Expr1008] = ([Expr1003], [Expr1006]), [Expr1009] = ([Expr1004], [Expr1007]), [Expr1010] = ([Expr1002], [Expr1005])

 次に、Merge Interval オペレーターでダブった範囲が消去されます。OrderDate > Expr1003 と OrderDate > Expr1006 から、Expr1008 = @min_date となります。OrderDate < Expr1004 と OrderDate < Expr1007 から、Expr1009 = @max_date となります。
 
 最後に Expr1008 と Expr1009 でシークを行ないます。

OBJECT:([AdventureWorks].[Sales].[SalesOrderHeader].[IX_SalesOrderHeader_OrderDate]), SEEK:([AdventureWorks].[Sales].[SalesOrderHeader].[OrderDate] > [Expr1008] AND [AdventureWorks].[Sales].[SalesOrderHeader].[OrderDate] < [Expr1009]) ORDERED FORWARD, FORCEDINDEX

 これは一例ですが、型の指定が間違っているだけで、SQL Server はこのような複雑な処理を行ないます。少しでも負荷を減らすためにも型を正しく指定しましょう。下記の型が正しいクエリを発行してみましょう。

-- datetime2 ではなく、datetime を指定する。
DECLARE @min_date datetime
DECLARE @max_date datetime

SET @min_date = '2011-05-31 00:00:00.000'
SET @max_date = '2011-07-31 00:00:00.000'

SET STATISTICS PROFILE ON

SELECT 
    SalesOrderID,
    RevisionNumber,
    OrderDate
FROM 
    Sales.SalesOrderHeader WITH (INDEX(IX_SalesOrderHeader_OrderDate))
WHERE 
    OrderDate > @min_date
AND OrderDate < @max_date

SET STATISTICS PROFILE OFF

 
 実行プランを参照すると、Computer Scalar、Concatenation, Merge Interval オペレーターが全て無くなっています。かなりスッキリしましたね。
f:id:koogucc11:20180820021533p:plain

 実行プランが単純化されることで、クエリの解析は高速化されますし、キャッシュプランのサイズも小さくなります。その結果、データベースサーバーへの負荷が軽減されます。条件に指定する型は正確に指定するように意識しましょう。

 SQL Server 2017 でのパフォーマンスチューニングはどう変わるんだろう。2012 で止まってる自分は未知の世界。

SQL Server 2017 Query Performance Tuning: Troubleshoot and Optimize Query Performance

SQL Server 2017 Query Performance Tuning: Troubleshoot and Optimize Query Performance

SQL Server Management Studio を触っていて、GO コマンドをみてふと Go のことを思い出したので、ちょっと勉強をしてみる

 今年のお盆休みは初の10連休でした。これだけ休みが長いとふと何かを勉強したくなるもんですね。最近はデータベースばかりでプログラミングに触れていませんでした。SQL Server を触っていて、GO コマンドを見たとき下記の記事を思いだしました。
codezine.jp

 求人数的には、RubyPython には及びませんが、年収では堂々一位です。今後人気が出そうですね。ミーハーなこともあり、早速 GO のお勉強を開始したいと思います(笑) ちょっとググってみるとわかりやすい記事がいくつも見つかります。下記のサイトが一番わかりやすそうです。
なぜGo言語 (golang) はよい言語なのか・Goでプログラムを書くべき理由

 悪い点がいくつか挙げられていました。

Generics (template) がない
継承がない
例外がない。まるで1970年代に設計されたかのようである。
非知的なプログラマのためにデザインされている。

 ここで、「非知的なプログラマのためにデザインされている。」という項目がありましたが、大規模プロジェクトになると様々なレベルの開発者が関わるため、この点は非常に重要だと感じます。知識のない開発者に継承や Generics などを下手に扱わせて、メンテナンス性などを落とすくらいなら、ある程度制限がある方がソースのレベルも一定に保てていいように思います。※ただ、やっぱり継承欲しいです。

 try catch finally などの例外処理がないとありますが、とりあえず手法は存在するようです。try に対応する defer を使って panic() 関数でコールした内容を catch にあたる recover() 関数で処理するようです。また、この defer,panic, recover は内部処理的なものに使うのが指針のようで、API レベルのものには error オブジェクトを使用するのが本流のようです。
blog.amedama.jp

 それ以外には、繰り返し処理には do や while は存在せず、for 分のみです。switch 文では case に条件を複数指定することができます。※ case 1,2,3,4 みたいに。

 たまに、言語を勉強するなら C++ を学べばどんな言語でもできるようになるという方もいらっしゃいますが、C++ が挫折する人も多く、開発言語を習得するにはハードルが高いように思えます。Go であれば習得も速く、言語習得するには最適なような気がします。(個人的意見です。)

 とりあえず Go の開発環境をインストールして見た。面白そうなので、しばらく触ってみよう。
f:id:koogucc11:20180819131934p:plain

みんなのGo言語【現場で使える実践テクニック】

みんなのGo言語【現場で使える実践テクニック】