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

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

SQL Server Management Studio の知っておいたほうが良い機能について挙げてみる - その12 - ( 列名の前後に [ ] を付けないへの要望 )

 ちょっと早起きしたので、記事書きます。前回の記事で、17.6 で対応されたオブジェクトエクスプローラーからの各情報をドラッグ&ドロップで [] を付加しないようにする機能を紹介しました。
ryuchan.hatenablog.com

 個人的には下記のパターンも対応してほしいです。あと、カンマの位置とかも制御できるといいですね。

  • テーブルをクリックする。
    f:id:koogucc11:20180324062546p:plain
  • 右クリックで、上位 n 件をクリックする。
    f:id:koogucc11:20180324065650p:plain
  • 列名およびテーブル名に [ ] が付加された SELECT 文が生成される。
    f:id:koogucc11:20180324062559p:plain

 このケースも [ ] を制御できるといいですね。ひとりごとです。

SQL Server Management Studio の知っておいたほうが良い機能について挙げてみる - その11 - ( 列名の前後に [ ] を付けない )

 しばらく、SQL Server Management Studio の機能について記事を書いていませんでした。
ryuchan.hatenablog.com

 SQL Server Management Studio 17.6 がリリースされました。
https://blogs.technet.microsoft.com/dataplatforminsider/2018/03/20/ssms-17-6-is-now-available-managed-instance-and-many-bug-fixes/

 細かい機能ですが、便利な設定が追加されていました。

Object Explorer: Added settings to allow users not to force brackets around names when dragging and dropping from Object Explorer to Query Window.

 早速設定してみましょう。

  • SQL Server management Studio を起動し、ツール→オプションをクリックします。f:id:koogucc11:20180321195359p:plain
  • Surround Object .. を false に設定します。f:id:koogucc11:20180324060606p:plain
  • テーブルを開きます。f:id:koogucc11:20180321202327p:plain
  • 列を選択します。f:id:koogucc11:20180321202338p:plain
  • ドロップします。f:id:koogucc11:20180321202349p:plain

列名に [ ] を付けずに展開することが可能になっています。細かい機能ですが、いい機能ですね。

 肉が食べたくなってきた。

熟成肉 肉バル CARNE BAR KATETE 虎ノ門店
〒105-0001 東京都港区虎ノ門1-16-2 B1
5,000円(平均)1,000円(ランチ平均)

 夏に向けて、色々購入。

 シュノーケルマスクなるものがあるかのか。
[asin:B079FH512G:detail]

大量の IN 句の動作を見てみた

 お久しぶりです。最近は、激しい移動すなわち、「 #ダイヤモンド修行 」 が激しさを増しており、記事さえ中々書けない事態に陥っています。今回はそんなのやるなら初めからちゃんと JOIN したりするのを前提にクエリ設計したらいいやん!と批判を浴びそうな気がしますが、ちょっと気になったので簡単に検証してみます。

下記のような恐ろしい クエリ1 と クエリ2 を用意します。
※クエリ1

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
    [AdventureWorks].[Sales].[SalesOrderHeader]
WHERE
    SalesOrderID IN('43659', '43660', '43661', '43662', '43663', '43664', '43665', '43666', '43667', '43668', '43669', '43670', '43671', '43672', '43673', '43674', '43675', '43676', '43677', '43678', '43679', '43680', '43681', '43682', '43683', '43684', '43685', '43686', '43687', '43688', '43689', '43690', '43691', '43692', '43693', '43694', '43695', '43696', '43697', '43698', '43699', '43700', '43701', '43702', '43703', '43704', '43705', '43706', '43707', '43708', '43709', '43710', '43711', '43712', '43713', '43714', '43715', '43716', '43717', '43718', '43719', '43720', '43721', '43722', '43723', '43724', '43725', '43726', '43727', '43728', '43729', '43730', '43731', '43732', '43733', '43734', '43735', '43736', '43737', '43738', '43739', '43740', '43741', '43742', '43743', '43744', '43745', '43746', '43747', '43748', '43749', '43750', '43751', '43752', '43753', '43754', '43755', '43756', '43757', '43758', '43759', '43760', '43761', '43762', '43763', '43764', '43765', '43766', '43767', '43768', '43769', '43770', '43771', '43772', '43773', '43774', '43775', '43776', '43777', '43778', '43779', '43780', '43781', '43782', '43783', '43784', '43785', '43786', '43787', '43788', '43789', '43790', '43791', '43792', '43793', '43794', '43795', '43796', '43797', '43798', '43799', '43800', '43801', '43802', '43803', '43804', '43805', '43806', '43807', '43808', '43809', '43810', '43811', '43812', '43813', '43814', '43815', '43816', '43817', '43818', '43819', '43820', '43821', '43822', '43823', '43824', '43825', '43826', '43827', '43828', '43829', '43830', '43831', '43832', '43833', '43834', '43835', '43836', '43837', '43838', '43839', '43840', '43841', '43842', '43843', '43844', '43845', '43846', '43847', '43848', '43849', '43850', '43851', '43852', '43853', '43854', '43855', '43856', '43857', '43858', '43859', '43860', '43861', '43862', '43863', '43864', '43865', '43866', '43867', '43868', '43869', '43870', '43871', '43872', '43873', '43874', '43875', '43876', '43877', '43878', '43879', '43880', '43881', '43882', '43883', '43884', '43885', '43886', '43887', '43888', '43889', '43890', '43891', '43892', '43893', '43894', '43895', '43896', '43897', '43898', '43899', '43900', '43901', '43902', '43903', '43904', '43905', '43906', '43907', '43908')

※クエリ2

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
    [AdventureWorks].[Sales].[SalesOrderHeader]
WHERE
    SalesOrderID IN('43873', '43660', '43824', '43739', '43694', '43898', '43902', '43713', '43700', '43664', '43661', '43745', '43708', '43901', '43741', '43794', '43848', '43755', '43888', '43687', '43813', '43670', '43781', '43840', '43817', '43857', '43853', '43759', '43815', '43810', '43711', '43750', '43830', '43723', '43698', '43754', '43879', '43748', '43778', '43777', '43753', '43870', '43742', '43728', '43691', '43668', '43702', '43707', '43818', '43811', '43780', '43847', '43763', '43784', '43837', '43680', '43860', '43862', '43866', '43821', '43906', '43838', '43699', '43861', '43894', '43666', '43751', '43785', '43872', '43725', '43877', '43744', '43782', '43798', '43743', '43752', '43662', '43793', '43676', '43683', '43747', '43677', '43796', '43667', '43669', '43867', '43722', '43709', '43718', '43692', '43829', '43730', '43881', '43726', '43773', '43834', '43825', '43695', '43688', '43889', '43712', '43800', '43826', '43775', '43899', '43799', '43885', '43789', '43684', '43802', '43740', '43845', '43863', '43703', '43724', '43736', '43704', '43721', '43792', '43882', '43904', '43682', '43851', '43842', '43895', '43774', '43868', '43900', '43729', '43779', '43672', '43887', '43675', '43673', '43832', '43880', '43697', '43831', '43874', '43749', '43883', '43823', '43905', '43715', '43737', '43701', '43858', '43731', '43766', '43689', '43714', '43852', '43735', '43764', '43772', '43686', '43890', '43756', '43762', '43706', '43787', '43822', '43807', '43671', '43770', '43681', '43804', '43679', '43801', '43841', '43720', '43833', '43908', '43827', '43812', '43797', '43663', '43816', '43719', '43850', '43814', '43907', '43876', '43896', '43871', '43819', '43835', '43839', '43884', '43659', '43761', '43765', '43768', '43705', '43696', '43674', '43869', '43854', '43859', '43886', '43678', '43716', '43769', '43795', '43892', '43808', '43878', '43685', '43844', '43710', '43803', '43903', '43786', '43836', '43809', '43849', '43843', '43746', '43897', '43864', '43790', '43875', '43856', '43805', '43791', '43734', '43733', '43776', '43846', '43727', '43820', '43788', '43690', '43865', '43738', '43665', '43771', '43767', '43828', '43758', '43783', '43757', '43893', '43855', '43693', '43806', '43891', '43732', '43717', '43760')

 クエリ1 の IN 句の条件は、SalesOrderID が昇順で並び替えられています。クエリ2 の IN 句の条件はランダムに並び替えられています。それぞれ計測してみます。

  • 1回目f:id:koogucc11:20180305001430p:plain
  • 2回目f:id:koogucc11:20180305001435p:plain
  • 3回目f:id:koogucc11:20180305001440p:plain
  • 4回目f:id:koogucc11:20180305001445p:plain
  • 5回目f:id:koogucc11:20180305001449p:plain

インデックスの並び順で IN 句指定されたほうが明らかに高速ですね。もう少し詳しくみてみましょう。SET STATISTICS PROFILE ON を付加します。
f:id:koogucc11:20180305002230p:plain

指定した IN 句の条件がきちんと並び替えられていますね。レスポンス差は内部的にこのソートの負荷が生じた結果なのでしょうか。

VALUES:(((43659)),((43660)),((43661)),((43662)),((43663)),((43664)),((43665)),((43666)),((43667)),((43668)),((43669)),((43670)),((43671)),((43672)),((43673)),((43674)),((43675)),((43676)),((43677)),((43678)),((43679)),((43680)),((43681)),((43682)),((43683)),((43684)),((43685)),((43686)),((43687)),((43688)),((43689)),((43690)),((43691)),((43692)),((43693)),((43694)),((43695)),((43696)),((43697)),((43698)),((43699)),((43700)),((43701)),((43702)),((43703)),((43704)),((43705)),((43706)),((43707)),((43708)),((43709)),((43710)),((43711)),((43712)),((43713)),((43714)),((43715)),((43716)),((43717)),((43718)),((43719)),((43720)),((43721)),((43722)),((43723)),((43724)),((43725)),((43726)),((43727)),((43728)),((43729)),((43730)),((43731)),((43732)),((43733)),((43734)),((43735)),((43736)),((43737)),((43738)),((43739)),((43740)),((43741)),((43742)),((43743)),((43744)),((43745)),((43746)),((43747)),((43748)),((43749)),((43750)),((43751)),((43752)),((43753)),((43754)),((43755)),((43756)),((43757)),((43758)),((43759)),((43760)),((43761)),((43762)),((43763)),((43764)),((43765)),((43766)),((43767)),((43768)),((43769)),((43770)),((43771)),((43772)),((43773)),((43774)),((43775)),((43776)),((43777)),((43778)),((43779)),((43780)),((43781)),((43782)),((43783)),((43784)),((43785)),((43786)),((43787)),((43788)),((43789)),((43790)),((43791)),((43792)),((43793)),((43794)),((43795)),((43796)),((43797)),((43798)),((43799)),((43800)),((43801)),((43802)),((43803)),((43804)),((43805)),((43806)),((43807)),((43808)),((43809)),((43810)),((43811)),((43812)),((43813)),((43814)),((43815)),((43816)),((43817)),((43818)),((43819)),((43820)),((43821)),((43822)),((43823)),((43824)),((43825)),((43826)),((43827)),((43828)),((43829)),((43830)),((43831)),((43832)),((43833)),((43834)),((43835)),((43836)),((43837)),((43838)),((43839)),((43840)),((43841)),((43842)),((43843)),((43844)),((43845)),((43846)),((43847)),((43848)),((43849)),((43850)),((43851)),((43852)),((43853)),((43854)),((43855)),((43856)),((43857)),((43858)),((43859)),((43860)),((43861)),((43862)),((43863)),((43864)),((43865)),((43866)),((43867)),((43868)),((43869)),((43870)),((43871)),((43872)),((43873)),((43874)),((43875)),((43876)),((43877)),((43878)),((43879)),((43880)),((43881)),((43882)),((43883)),((43884)),((43885)),((43886)),((43887)),((43888)),((43889)),((43890)),((43891)),((43892)),((43893)),((43894)),((43895)),((43896)),((43897)),((43898)),((43899)),((43900)),((43901)),((43902)),((43903)),((43904)),((43905)),((43906)),((43907)),((43908)))

時間あったら、読んでみたい。

SQL Server 2017 Administrator's Guide

SQL Server 2017 Administrator's Guide

新年の挨拶してみる

 新年あけましておめでとうございます。旧年は大変お世話になりました。今年も【都内で働くSEの技術的なひとりごと】のご購読よろしくお願いいたします。今年もダイヤモンド修行頑張りますww
f:id:koogucc11:20180101141908p:plain

今年書いた記事を振り返ってみる

 今年は去年と比較すると、投稿数は激減しました。
f:id:koogucc11:20171231230142p:plain

 去年は、120。今年は36。
f:id:koogucc11:20171231230337p:plain

 今年は特に新しいことにも取り組まず、仕事に忙殺されていた感じです。そういう今も仕事の合間に書いてます。来年はもう少しテクニカルなことに取り組まないとなぁと思ってます。あと、オープンソース

 来年もどうぞよろしくお願いいたします。それでは、よいお年をお迎えください♪
 

反省

反省

デッドロックについて説明してみる - その 7 ( C# から sp_getapplock と sp_releaseapplock 使ってデッドロックを回避してみる ) -

 過去に C# からデッドロックを例外処理でキャッチするサンプルを作成しました。
ryuchan.hatenablog.com

 このサンプルソースに、p_getapplock と sp_releaseapplock を適用し、デッドロックを回避します。まず、それぞれのストアドをコールするロジックを作りましょう。

public int GetAppLock(SqlConnection connection, SqlTransaction transaction)
{
    var command = new SqlCommand("sp_getapplock", connection, transaction);
    command.CommandType = CommandType.StoredProcedure;
    command.CommandTimeout = 60000;

    command.Parameters.AddWithValue("Resource", "lock_resource_id");
    command.Parameters.AddWithValue("LockMode", "Exclusive");
    command.Parameters.AddWithValue("LockOwner", "Transaction");
    command.Parameters.AddWithValue("LockTimeout", 60000);

    var retCode = command.Parameters.Add("ReturnValue", SqlDbType.Int);
    retCode.Direction = ParameterDirection.ReturnValue;
    command.ExecuteNonQuery();

    return (int)retCode.Value;
}

public int ReleaseAppLock(SqlConnection connection, SqlTransaction transaction)
{
    var command = new SqlCommand("sp_releaseapplock", connection, transaction);
    command.CommandType = CommandType.StoredProcedure;
    command.CommandTimeout = 60000;

    command.Parameters.AddWithValue("Resource", "lock_resource_id");

    var retCode = command.Parameters.Add("ReturnValue", SqlDbType.Int);
    retCode.Direction = ParameterDirection.ReturnValue;
    command.ExecuteNonQuery();

    return (int)retCode.Value;
}

 下記のように組み込みます。

using (SqlConnection connection = new SqlConnection(connectionString))
{
    connection.Open();
    var command = connection.CreateCommand();

    while (0 == 0)
    {
        try
        {
            var transaction = connection.BeginTransaction("query1");
            if (GetAppLock(connection, transaction) >= 0)
            {

                command.Connection = connection;
                command.Transaction = transaction;

                command.CommandText = @"UPDATE 
                            Production.Product
                        SET Name = N'Bearing Ball'
                        WHERE
                            ProductID = 2;";
                command.ExecuteNonQuery();

                command.CommandText = @"UPDATE 
                            Production.Product
                        SET Name = N'Adjustable Race'
                        WHERE
                            ProductID = 1;";
                command.ExecuteNonQuery();
            }
            ReleaseAppLock(connection, transaction);
            transaction.Commit();
            transaction.Dispose();
        }
        catch (SqlException ex)
        {
            MessageBox.Show("エラーNo:" + ex.Number.ToString() + " エラーメッセージ:" + ex.Message.ToString());
            break;
        }
    }
    command.Dispose();
}

 組み込みが完了したら、実行してみましょう。デッドロックが発生しません。dm_tran_locks でアプリケーションロックが発生しているのが判断できます。
f:id:koogucc11:20171230125822p:plain

 LockOwner が Transaction の場合は、明示的に sp_releaseapplock はコールしなくてもいいようですが、個人的に気持ち悪いのでサンプルソースでは呼んでます。さて、今年も残すところあと2日。けど、私は明日から一月中旬までずっとお仕事です....いつになったら、ゆっくり正月を迎えられるようになるんでしょうか....

好奇心を“天職

好奇心を“天職"に変える空想教室

天職は寝て待て?新しい転職・就活・キャリア論? (光文社新書)

天職は寝て待て?新しい転職・就活・キャリア論? (光文社新書)