ITC シュウちゃん のすべての投稿

インデックス再構築・再構成(SQL Server)

ITコーディネータのシュウです。

IMG_1531

先日、妻の実家のある富山のほうに行く機会があり、そこできれいな夕焼けが見れたので、撮った写真です。車に乗っていた娘が、きれいだよ!というので、慌てて車の中から撮ったものです。
そのときも、本当に昼間は暑い日が続いていて、これは大変だと思っていましたが、その後もさらに暑さが増して、今年は本当に危険な暑さになってますよね。埼玉の熊谷では、41.1℃という、国内最高気温を更新するという状況になりました。クーラーが効いていないところでは、本当に大変かと思います。
皆さん、本当にお体には注意して頂きたいと思います。

<本日の題材>
インデックス再構築・再構成(SQL Server)

前回、SQL Serverの動的管理ビューを使用することで、パフォーマンスに影響があるクエリーの確認や不足しているインデックスなどを確認できることをブログで取り上げましたが、今回もその続きということで、取り上げてみたいと思います。
データベースはインデックスをうまく設定することで、抽出処理のレスポンスを効果的に向上させることができますが、当初それほど遅くなかった抽出処理が、いつの間にかとても遅くなっていることに気づくことがあります。その原因の一つに、インデックスの断片化というものがあります。

以前、大手企業の分析用のシステムを見ていたときがありました。日々基幹システム側から日次のデータが分析用のデータベースに送られてくるので、削除・登録などの処理を夜間に行って、分析用データベースを本番環境の前日終わり時点のデータにしていました。毎日、大量のトランザクションデータがあるため、夜間に送られてくるデータもかなりのボリュームがあり、夜間バッチ処理も結構な時間がかかっていました。
そして、分析用に作成したクエリーやプロシージャなどの処理が、作成した当初はそれほど遅くなかったのに、とても遅いと感じるようになることがありました。
原因を調べてみると、インデックスの断片化がかなりの割合で発生しており、ページ密度が大きく低下し、読み取りのページ数もその分多くなって、効率が悪くなっていたことが大きな要因でした。
当時は、SQL Server 2000を使っていたので、DBCC SHOWCONTIG コマンドで断片化を確認し、DBCC DBREINDEXコマンドで再構築を行ったり、 DBCC INDEXDEFRAGコマンドで再構成を行ったりということを、不定期に行っていました。

今は、SQL Server のバージョンも上がり、動的管理ビューを使用することで、インデックスの断片化も確認できます。以下がそのSQLの例になります。

SELECT DB_NAME(s.database_id), OBJECT_NAME(s.object_id), s.index_type_desc, i.name, s.page_count,s.fragment_count, s.avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID('dbsdb'), NULL, NULL, NULL, 'LIMITED') s
INNER JOIN sys.indexes i ON i.object_id = s.object_id
  and i.index_id = s.index_id
WHERE s.avg_fragmentation_in_percent > 10
ORDER BY avg_fragmentation_in_percent DESC

断片化1

ここでの、主な項目の意味としては、
page_count                                                 ページ数
fragment_count                                       断片化しているページ数
avg_fragmentation_in_percent      断片化の割合(%)

上記の結果では、断片化の割合が10%以上のものを抽出していますが、結構高い割合のものがあることが確認できます。

また、抽出SQLのdm_db_index_physical_stats 関数の5番目の引数であるスキャンモードには、LIMITED, SAMPLED, DETAILEDの3種類があります。(上記の例は、LIMITED モード)
それぞれのスキャンモードの意味は以下になります。

LIMITED           
        最も高速なモードで、スキャンするページ数は最小

SAMPLED         
        SAMPLED モードでは、インデックスまたはヒープの全ページの 1% のサンプルに基づく統計情報が返されます。インデックスまたはヒープのページが 10,000 ページに満たない場合は、SAMPLED モードの代わりに DETAILED モードが使用されます。
 
DETAILED       
        DETAILED モードではすべてのページがスキャンされ、すべての統計が返されます。

それで、断片化を解消するには、以下の3つの方法があります。1)     インデックスのオフライン再構築
2)     インデックスのオンライン再構築(Enterprise エディション のみで利用可能)
3)     インデックスの再構成

1)     インデックスのオフラインでの再構築のコマンドは以下になります。

ALTER INDEX インデックス名 ON テーブル REBUILD

インデックスの再構築(オフライン)は、新しい領域へインデックスを再作成し、古いインデックスを削除することで、断片化を解消します。したがって、インデックスの再構築中は、インデックス全体がロックされるので、再構築が完了するまでは、ユーザー操作は待ち状態になり、注意が必要です。

例)
ALTER INDEX PK_T_USER_LOG ON dbo.T_USER_LOG REBUILD

インデックス再構築_v8_1

再構築の後で、再度このテーブルについての断片化を見てみます。

SELECT DB_NAME(s.database_id), OBJECT_NAME(s.object_id), s.index_type_desc, i.name, s.page_count, s.fragment_count, s.avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID('dbsdb'), OBJECT_ID(N'T_USER_LOG'), NULL, NULL, 'LIMITED') s
INNER JOIN sys.indexes i ON i.object_id = s.object_id
  and i.index_id = s.index_id;

インデックス再構築後_v8_2

上記の結果から、断片化の割合は 0% になり、断片化が解消されたことがわかります。

2)     インデックスのオンライン再構築のコマンドは以下になります。

ALTER INDEX インデックス名 ON テーブル REBUILD WITH ONLINE = ON

3)     インデックスの再構成のコマンドは以下になります。

ALTER INDEX インデックス名 ON テーブル REORGANIZE

例)
先ほどの、断片化の一覧で、断片化が35%程度であった、「T_USER_LOG_V6」について、再構成を行ってみます。最初に、現状の断片化を再度確認してみます。

SELECT DB_NAME(s.database_id), OBJECT_NAME(s.object_id), s.index_type_desc, i.name, s.index_id, s.alloc_unit_type_desc, s.page_count, s.fragment_count, s.avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID('dbsdb'), OBJECT_ID(N'T_USER_LOG_V6'), NULL, NULL, 'LIMITED') s
INNER JOIN sys.indexes i ON i.object_id = s.object_id
and i.index_id = s.index_id;

インデックス再構成前_3

再構成を実施してみます。

ALTER INDEX PK_T_USER_LOG_V6 ON dbo.T_USER_LOG_V6 REORGANIZE;

インデックス再構成後_4

件数が多少多かったこともあり、少し時間がかかった感じがありました。

断片化を再度確認してみます。先ほどと同じSQLを実行してみます。

インデックス再構成後_5

先ほど35%程度あったところは、2.4% ほどに変わりました。断片化がかなり解消されたことがわかります。

★インデックスの再構築と再構成の違いについて簡単に記します。
〇再構築
・ひとつのトランザクションでインデックスを完全に再作成。
 そのため、キャンセルすればそのトランザクションはロールバ
 ックされ、断片化した状態に戻る。
・インデックスを作り直すので、テーブルのレコード数が増えな
 い限り、大きく処理時間が変わることはない。
・一時的には、断片化した古いインデックスと再作成した新しい
 インデックスがふたつ存在する状況となり、それらを格納する
 ための容量、及びソート用の領域が必要になる。

〇再構成
・処理単位ごと (処理単位はページ) にトランザクションが分割さ
 れていて、リーフページ間でインデックス行を移動させること
 で行を前に詰めて断片化を解消している。
 キャンセルしても、既に完了しているトランザクションの結果
 は維持される。
・前のページに空きがある場合に後ろのページから前のページへ
 行を移動するという処理であるため、断片化の度合が大きいほ
 ど処理時間が長くなる。
・追加の領域は基本的には必要としない。

実際の運用では、上記のような違いを考慮してどちらを選択するかを決定する必要があると思います。

今日は以上まで

にほんブログ村 IT技術ブログへ
にほんブログ村

動的管理ビュー(SQL Server)

ITコーディネータのシュウです。

IMG_1498

いよいよ梅雨の季節が近づいてきました。上の写真は、少し前に娘がスマホで撮って送ってくれたきれいな夕方の空です。少し神秘的ですね。梅雨になるとこういう空もなかなか見れなくなっちゃうな。
さて、最近のスポーツでは、サッカーのワールドカップがいよいよ始まります。2か月前に監督の交代劇があり、このところの強化試合も負け続けているので、難しいと思っちゃいますが、どうか奇跡よ起きて~! 2002年の日韓共催のワールドカップのベスト16を超えてほしい!
また、卓球では先日の荻村杯・ジャパンオープンで、男子は張本智和選手、女子では伊藤美誠選手が優勝しました。接戦を最後まで粘って勝ち切った精神力は本当にすごい、感動します。日本選手が頑張っていると、元気が湧いてきます。よーし、仕事も頑張るぞー!

<本日の題材>
動的管理ビュー(SQL Server)

SQL Serverを使用していて、パフォーマンスがいまいちよくない場合など、最もCPUを多く使っているクエリーは何か?、最も多くのI/Oを発生させているクエリは何か?、不足しているインデックスはないか?などを確認したくなることがあると思います。そんなときに、知っていると便利な動的管理ビューについて、今回は取り上げてみたいと思います。

SQL Serverというと、パフォーマンスモニターや利用状況モニターなど、GUIのツールでいろいろと調べるというイメージが強く、逆にOracleは、V$表といわれる動的パフォーマンスビューなどを駆使していろいろと調べるというイメージが強いですね。(最近はOracleもEnterprise ManagerなどでGUIでも見れるかたちにしてきていますが)
ただ、SQL Serverでも、動的管理ビューというものから、いろいろと上記のような内容を調査することができます。
ちなみに、動的管理ビュー(DMV:Dynamic Management View)は、SQL Server2005で追加された機能で、パフォーマンス・チューニングを手掛けるエンジニアにとっては画期的といえるものでした。それまで、ほとんどドキュメント化されず、その状態を参照する方法も知らされていなかったSQL Serverの内部が、広く可視化されたからです。
それでは、以下に例を挙げてみましょう。

●最もCPUを多く使っているクエリーの上位10位までを確認する

SELECT TOP 10
  total_worker_time/execution_count AS avg_cpu_cost,
  execution_count,
  SUBSTRING(st.text, (qs.statement_start_offset/2)+1, 
        ((CASE qs.statement_end_offset 
         WHEN -1 THEN DATALENGTH(st.text) 
        ELSE qs.statement_end_offset 
        END - qs.statement_start_offset)/2) + 1) AS query_text,
  query_plan
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS st
CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS qp
ORDER BY avg_cpu_cost DESC;

avg_cpu_cost

上記は、「sys.dm_exec_query_stats」という動的管理ビューから抽出できる情報で、「total_worker_time」(プランの実行で使用されたcpu時間の合計)を「execution_count」(プランが実行された回数)で割った値を平均のcpuコストとして、それの多い順に10件を表示しています。ただし、実行頻度(execution_count)が少なければ、それほど重要ではないと思われます。
(※注意点としては、現在キャッシュされているクエリに対する集計情報のみを示していること。メモリが多くなければ、過去に行ったコストの高いクエリがキャッシュから削除されている可能性もあるので、定期的にこの抽出を行えば、コストの高いクエリを特定できる可能性が高くなると思われます。)

なお、上記のSQLでは、前回取り上げた「CROSS APPLY」を使用しています。また、「querry_plan」の列を最後に表示していますが、これをクリックすると、以下のように「querry_text」で表示されたSQLの実行時の実行プランが表示できます。(ただし、一緒に表示するとその分抽出処理が重たくなると思われるので、後から plan_handleを元に実行プランを抽出することも可能です。)

querr_plan

参考:https://docs.microsoft.com/ja-jp/sql/relational-databases/system-dynamic-management-views/sys-dm-exec-query-stats-transact-sql?view=sql-server-2017

●最も多くのI/Oを発生させているクエリの上位10位までを確認する

SELECT TOP 10
  (qs.total_logical_reads/qs.execution_count) AS avg_logical_reads,
  (qs.total_logical_writes/qs.execution_count) AS avg_logical_writes,
  (qs.total_physical_reads/qs.execution_count) AS avg_phys_reads,
  execution_count,
  SUBSTRING(st.text, (qs.statement_start_offset/2)+1, 
        ((CASE qs.statement_end_offset 
         WHEN -1 THEN DATALENGTH(st.text) 
        ELSE qs.statement_end_offset 
        END - qs.statement_start_offset)/2) + 1) AS query_text,
  query_plan
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS st
CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS qp
ORDER BY (total_logical_reads + total_logical_writes) DESC;

io_top10

 こちらは、「total_logical_reads」(論理読み取りの合計数)と「total_logical_writes」(論理書き込みの合計数)の合計の多いものから順に上位10件を表示しています。

●不足していると思われるインデックスの一覧

SELECT gs.avg_user_impact AS [予測されるクエリパフォーマンス改善率],
       gs.avg_total_user_cost AS [削減できたクエリの平均コスト],
       gs.last_user_seek AS [最後にシークした時間],
       id.statement AS [テーブル名] ,
       id.equality_columns AS [等値述語に使用できる列],
       id.inequality_columns AS [不等値述語に使用できる列] ,
       id.included_columns AS [包括列として必要な列],
       gs.unique_compiles AS [コンパイルおよび再コンパイルの数],
       gs.user_seeks AS [クエリによって発生したシーク数]
FROM  sys.dm_db_missing_index_group_stats AS gs
       INNER JOIN sys.dm_db_missing_index_groups AS ig
                                          ON gs.group_handle = ig.index_group_handle
       INNER JOIN sys.dm_db_missing_index_details AS id
                                          ON ig.index_handle = id.index_handle
-- WHERE id.[database_id] =DB_ID(‘db名’)
   -- コメントをはずすと指定したデータベースでの抽出となる
Order By gs.avg_user_impact DESC;

インデックス不足

 上記は、「sys.dm_db_missing_index_group_stats」「sys.dm_db_missing_index_groups」「sys.dm_db_missing_index_details」という動的管理ビューから抽出できる情報で、インデックスが存在していたなら改善されるであろうパフォーマンス改善率などを表示するものになっています。
上記の動的管理ビューの結果からインデックスを追加作成するとした場合には、[equality_columns(等値述語に使用できる列)]を最初に指定し、その次に、[inequality_columns(不等値述語に使用できる列)]を指定し、INCLUDE句に[included_columns(包括列として必要な列)]を指定するかたちになります。

※参考:https://docs.microsoft.com/ja-jp/previous-versions/sql/sql-server-2008-r2/ms345405(v=sql.105)

例えば、1番目の結果からインデックスを追加するとしたら、

CREATE NONCLUSTERED INDEX [KEY1_製品区分別積上] ON [dbo].[製品区分別積上]
(
              [年度], [月], [バージョン], [部門コード], [製品区分], [製品項目]
)
INCLUDE (
[金額], [粗利率], [粗利額]
);

レスポンス改善を行いたいときに、結構有効かも知れませんね。

今日は以上まで

にほんブログ村 IT技術ブログへ
にほんブログ村

APPLY(SQL Server)

ITコーディネータのシュウです。

IMG_1412

自宅から会社に行く途中に道路のそばに咲いているポピーの花です。自転車で通るので、きれいに咲いているときには少し止まって眺めたりするこの頃ですが、若いときは、頭の中は仕事のことか、差し迫ったやるべきことなどでいっぱい(もしくはぼーっとしている?)で、見ていても記憶に残らないという感じだったと思います。妻にあそこにきれいな花が咲いているでしょう?と聞かれても、そうだっけ?という返事をするので、そういう感覚が欠落しているかわいそうな人だとあきれられていたものですが、少しずつ花などの自然も意識するようになってきました。

ちなみに、ポピーは色とりどりの花を咲かせるケシ科の植物の総称で、その実から採れる乳液には、入眠や麻痺の作用があることから、紀元前400年頃のギリシアでは麻酔薬や睡眠導入薬として用いられていたそうです。花言葉も「なぐさめ」「心の平静」「いたわり」「思いやり」などその効能にちなんだものが多くあり、相手をいたわる気持ちや、助けたい気持ちを表現するときによく贈られる花だそうです。

<本日の題材>
APPLY(SQL Server)

今回は、APPLYという演算子について取り上げてみます。
以前、テーブル値関数について記事として載せたことがありますが、あるテーブルのデータの値と、その値によって取得されるテーブル値関数の結果を組み合わせて抽出したいという場合に、APPLY という演算子を使用することができるようです。(SQL Server 2005から)
SQLのFROM句の後に、まずテーブルを記載し、「CROSS APLLY」、もしくは「OUTER APPLY」の後側にテーブル値関数を指定するかたちになり、SELECT のほうではテーブルの列とテーブル値関数の結果の列を含めるかたちになります。
私も今まであまり使ったことがなかったのですが、今回、試してみようと思います。

例)
使用するテーブルは、以前ブログで使ったことのある、日本の都道府県、山、川、湖などの大きさや高さや長さなどをデータにしたランキングのデータを使ってみたいと思います。
今回使用するテーブル(「ランキング」「ランキング区分」)の定義は、下記のような設定。

テーブル定義

データを抽出してみると、
「ランキング区分」テーブルは、

ランキング区分データ

「ランキング」テーブルは、

ランキングデータ

今回使用するテーブル値関数は、「区分NO」の値からランキングテーブルのデータを抽出する簡単なものです。定義は以下:

CREATE FUNCTION [dbo].[ufn_ランク上位取得]
(
         @p区分NO DECIMAL(4,0)
) RETURNS @ランク上位 TABLE (
         区分名 VARCHAR(40),
         ランキング DECIMAL(3,0),
         名称 VARCHAR(40),
         数値 DECIMAL(8,1)
)
AS
BEGIN
         INSERT @ランク上位
         SELECT
                   K.区分名
                  ,RANK() OVER (ORDER BY R.数値 DESC)
                  ,R.名称
                  ,R.数値
         FROM dbo.ランキング R
         JOIN dbo.ランキング区分 K ON R.区分NO = K.区分NO
         WHERE K.区分NO = @p区分NO;
 
        RETURN;
END;

このテーブル値関数にパラメータを直接指定して抽出すると、

SELECT * FROM dbo.ufn_ランク上位取得(1)
ORDER BY ランキング;

テーブル値関数抽出

これを、「ランキング区分」テーブルの「区分NO」をテーブル値関数にセットして、「区分NO」毎にランキング情報を抽出するように、APPLY句を使用すると、以下のように抽出できます。

SELECT K.区分NO, K.区分名, K.単位, R.ランキング, R.名称, R.数値
  FROM dbo.ランキング区分 K
  CROSS APPLY dbo.ufn_ランク上位取得(K.区分NO) AS R
ORDER BY K.区分NO, R.ランキング;

CROSSAPPLY

ここで、「ランキング区分」テーブルにあっても、テーブル値関数で結果のないものは抽出されないのですが、外部結合のように、上記のようなデータも左側のランキング区分の情報は表示し、テーブル値関数側の結果は null で表示したい場合には、「OUTER APPLY」演算子を使用します。

SELECT K.区分NO, K.区分名, K.単位, R.ランキング, R.名称, R.数値
  FROM dbo.ランキング区分 K
  OUTER APPLY dbo.ufn_ランク上位取得(K.区分NO) AS R
ORDER BY K.区分NO, R.ランキング;

OUTERAPPLY

 上記のように、「区分NO」=2, 3 のテーブル値関数では抽出されないデータも表示されることが確認できます。

ちなみに、APPLY演算子の右側は必ずテーブル値関数である必要はなく、上記の内容は、以下のようなSQLでも抽出できます。(CROSS APPLYの例)

SELECT K.区分NO, K.区分名, K.単位, RK.ランキング, RK.名称, RK.数値
  FROM dbo.ランキング区分 K
  CROSS APPLY
   (SELECT
                   K.区分名
                  ,RANK() OVER (ORDER BY R.数値 DESC) AS ランキング
                  ,R.名称
                  ,R.数値
         FROM dbo.ランキング R
         WHERE R.区分NO = K.区分NO) AS RK
ORDER BY K.区分NO, RK.ランキング;

CROSSAPPLY2

今まではあまり使ったことはなかったのですが、今後は、使えるときもあるのではないかと思います。

今日は以上まで

にほんブログ村 IT技術ブログへ
にほんブログ村

バインド変数(Oracle)

ITコーディネータのシュウです。

IMG_1388

ゴールデンウイークも終わり、ときに夏を思わせるような暑い日もある5月も後半になりました。
上の写真は、ゴールデンウイークに家族で群馬県館林市にあるつつじが岡公園のつつじまつりに行ってきたときのものです。
樹齢800年を超えるヤマツツジの巨樹群が自然形のままで保存され、歴史的価値も高いとのことです。時期的には少し遅かったので、見頃の時期は過ぎてしまっていましたが、それでもまだ咲いているつつじは結構あって、たくさんのお客様で賑わっていました。海外の人も結構いましたね!
天気がよくて気持ちよかったです。ちょっとでも自然に触れるのはいいものですね。
なかなか家族サービスができない現状だけど、少しは喜んでくれたかな(^^!

<本日の題材>
バインド変数(Oracle)

SQLでパフォーマンスを改善させる方法、及びセキュリティの観点からSQLインジェクションを防ぐ方法ということで、バインド変数を使うということがよく話題に上がります。今回は、Oracle環境でのバインド変数について取り上げてみたいと思います。
バインド変数とは、SQL文に埋め込む変数のことで、実際の値を後から設定できるようにSQL文の一部を変数にしたもので、これを利用することで、SQL文の記述を統一する(データベースからみて同一のものとみなせる)ことができます。

OracleがSQLを実行するステップは、大きくは以下のようになっています。
・解析処理(PARSE)
・実行処理(EXECUTE)
・データの取り出し処理(FETCH:SELECT文のときのみ)

解析処理には、構文チェック、表・列の定義チェック、権限チェック、実行計画の生成などが含まれ、一度解析したSQLは実行計画とともにSGAの共有プールのライブラリキャッシュにキャッシュされます。
SQLが発行されると、Oracleはライブラリキャッシュに同一のSQLの解析結果がキャッシュされていないかを確認し、キャッシュされていればそれ以降の解析処理をスキップして、キャッシュ上の実行計画を使ってSQLを実行します。(このことをSOFT PARSEと呼びます)
同一の解析結果が存在しない場合、上記の解析処理を実行しますが、このHARD PARSEが比較的重たい処理のために、これを省くことができればスループットの向上に繋がります。

そして、この共有プールにキャッシュされた情報は、SQLが完全に一致するときのみ再利用されるため、条件値が異なったり、SQL文の大文字・小文字や改行位置、スペースの個数など一部でも異なると違うSQLとして新しく解析されてしまいます。こういう仕組みのため、バインド変数を使うことで同一のSQLとみなせれば、HARD PARSEを回避できるというメリットがあります。
(ちなみに、SQLのソースコードの中に、直接記述した数値や文字列のことをリテラルと呼びます)

具体的に試してみます。
以前、バルク処理というところで作成した顧客テーブル(20万件)を使って、SELECT文の処理速度をリテラルの場合とバインド変数を使った場合で比較してみます。

テーブル定義は以下:

CREATE TABLE customer(
 c_id number(8)
,c_name varchar2(20)
,Constraint PK_customere Primary key(c_id));

テストデータを作成します。

BEGIN
 FOR i IN 1..200000 LOOP
   INSERT INTO customer(c_id, c_name) VALUES(i, '
顧客名_'||LPAD(TO_CHAR(i),8,'0'));
 END LOOP;
END;
/

このデータを、バインド変数を使わずに、主キーである c_id 列の値で SELECTしてみます。以前、実行の度にSQLが変わる場合について、動的SQLのEXECUTE IMMEDIATE文を使用する方法について取り上げたことがありましたが、今回もそれを使ってみます。

時間を計測したいので、時間の計測を可能にします。
SET TIMING ON

BEGIN
   FOR I IN 1..200000 LOOP
    EXECUTE IMMEDIATE 'SELECT * FROM customer WHERE c_id = ' || TO_CHAR(I);
   END LOOP;
END ;
/

動的sqlリテラル

3分2秒かかりました。

それでは、次は c_id = の条件のところを、バインド変数を使って行ってみます。
処理時間を厳密に確認するために、一旦、バッファキャッシュ、共有プールの情報をクリアします。

ALTER SYSTEM FLUSH  BUFFER_CACHE;
ALTER SYSTEM FLUSH SHARED_POOL;

メモリクリア

先ほどのSELECTの処理を、バインド変数を使って実行します。
 
BEGIN
    FOR I IN 1..200000 LOOP
        EXECUTE IMMEDIATE 'SELECT * FROM customer WHERE c_id =:C1' USING I;
             -- :C1 のところがバインド変数 、USING I で変数 I を使用
    END LOOP;
END ;
/

動的sqlバインド変数

5秒あまりで処理が終了しました。全然違いますね。

実際に、for loop 処理で生成したSELECT文について、共有SQL領域についての統計情報を示すV$SQLを抽出して確認してみます。 

select count(*) from V$SQL where SQL_TEXT like 'SELECT * FROM customer WHERE c_id%';

v$sql_統計情報

結果は1件と出ましたので、20万回のSELECT文がすべて同じ1回のSQL文を共有したということがわかります。実行計画を生成する HARD PARSEは1回のみであり、残りはすべて共有プール上のその実行計画を使って行ったということですね。

今回は、バインド変数を使うことで処理が非常に高速化しましたが、そうならないケースもあるようです。それについては、今回は特には記述はしませんが、また機会があれば確認してみたいと思います。

今日は以上まで

にほんブログ村 IT技術ブログへ
にほんブログ村

OVER句(Oracle)

ITコーディネータのシュウです。

IMG_1325

4月も終盤を迎え、もうすぐゴールデンウイークですね。
先日、埼玉県の埼玉県比企郡滑川町にある、国営武蔵丘陵森林公園に行ってきました。長年埼玉にいながら、実は行ったことがなかったのですが、東京ドーム65個分の広さがあり、雑木林にはたくさんの木があって、ストレス解消、森林浴にはもってこいの場所だと思いました。上の写真はハーブガーデンというハーブがいろいろと植えられているところの写真です。
下の写真は、ネモフィラという花が咲いている花畑です。

IMG_1352

日本には17個くらいの国営の公園があるのですが、ここが一番最初に整備されたところだそうです。
季節によっていろいろと見れる花もあり、サイクリングコースや子供が遊べるキッズコーナー、日本一大きなエアートランポリンなど、いろいろと楽しめそうです。ゆっくり歩いたので、一部しか回れませんでしたが、今度また家族で行こうかと思いました。
埼玉にも、探せばいろんないいところがありますね。今まで忙しさにかまけて行かなかったのが本当に残念!
子供が小さいときに、もっと自然と触れ合う機会を持つようにすればよかったね、と妻と話をすることが増えた今日この頃です。

<本日の題材>
OVER句(Oracle

前回、SQL Serverに関して、OVER句のROWSというものを題材に取り上げてみましたが、Oracleでも同様のことはできるのか?ということを調べてみたところ、以前からできるようなので、今回はOracleで確認してみたいと思います。

OracleでもOVER句と一緒に以下のような句が使用できます。

前後の行の値を取得する
LAG
--- 前の行
LEAD
--- 後の行

前回の例でも見た移動平均や移動累計の取得
ROWS n PRECEDING
--- 現在の行からn行前を含めて対象とする

最初の行、最後の行、n番目の行
FIRST_VALUE
--- パーティションの最初の行
LAST_VALUE
--- パーティションの最後の行
NTH_VALUE
--- パーティションのN番目の行

※上記で、IGNORE NULLS という句を付けると、NULL以外で最初、最後などの指定ができる

OVER句やPARTITION BY句を絡めた書き方としては、

LAG(項目名)
OVER (PARTITION BY 項目名1
     ORDER BY 項目名2
     )

項目名1ごとに、項目名2の並び順で、項目名の前の行の値(LAG)、項目名の後の行の値(LEAD)を抽出します。

LAG(項目名)のところは、以下のような設定が可能
LEAD(項目名)
FIRST_VALUE(項目名)
LAST_VALUE(項目名)

※LAG、LEADの代わりにSUM(項目名)、MAX(項目名)なども使えます。

例として、前回SQL Serverで行ったオリンピックのメダル数の抽出の例をOracleでも試してみます。

テーブルは以下の定義:
CREATE TABLE olympic_medal(
 season VARCHAR2(4)
,year   DECIMAL(4)
,color  VARCHAR(2)
,counts     INT
,CONSTRAINT pk_olympic_medal PRIMARY KEY (season, year, count));

このテーブルに、夏季、冬季の日本が取ったメダル数を登録してみます。(前回と同様にデータをInsertします。途中省略)

INSERT INTO olympic_medal VALUES('夏季',1912,'金',0);
INSERT INTO olympic_medal VALUES('夏季',1912,'銀',0);
INSERT INTO olympic_medal VALUES('夏季',1912,'銅',0);

INSERT INTO olympic_medal VALUES('冬季',2018,'金',4);
INSERT INTO olympic_medal VALUES('冬季',2018,'銀',5);
INSERT INTO olympic_medal VALUES('冬季',2018,'銅',4);

夏季、冬季それぞれの、各年毎、メダル色毎のメダル数(前回、次回も含めて)と、直近3回のメダル色毎の合計数、平均数を抽出し、年の新しい順に抽出してみます。

--まず出力結果のフォーマットを設定します。
col 季節 format a4
col 年 format 9999
col 色 format a4
col 今回 format 9999
col 前回 format 9999
col 次回 format 9999
col 直近3回合計 format 9999
col 直近3回平均 format 9999

--以下がSQL
SELECT
 season 季節
,year 年
,color 色
,counts 今回
,LAG(counts)
   OVER (PARTITION BY season, color
     ORDER BY year
     ) AS 前回
,LEAD(counts)
   OVER (PARTITION BY season, color
     ORDER BY year
     ) AS 次回
,SUM(counts)
   OVER (PARTITION BY season, color
     ORDER BY year
     ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
     -- 現在の行から2行前から現在行までの3行分
     ) AS 直近3回合計
,AVG(counts)
   OVER (PARTITION BY season, color
     ORDER BY year
     ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
   -- 現在の行から2行前から現在行までの3行分
     ) AS 直近3回平均
FROM olympic_medal
ORDER BY season, year DESC, color;

86_1

次に、金、銀、銅で色を分けずに、季節、年毎のメダル数の合計について、最初からの累計の合計個数と平均個数を抽出し、冬季、夏季の年の新しい順に表示してみます。

col 季節 format a4
col 年 format 9999
col 色 format a4
col 今回 format 9999
col 累計の合計 format 9999
col 累計の平均 format 9999

WITH C_YEAR_MEDAL(season, year, counts) AS
(SELECT season, year, SUM(counts)
   FROM olympic_medal
GROUP BY season, year
)
SELECT
season
,year
,counts
,SUM(counts)
   OVER (PARTITION BY season
     ORDER BY year
     ROWS BETWEEN UNBOUNDED PRECEDING
         AND CURRENT ROW     -- 最初の行から現在行まで
     ) AS 累計の合計counts
,AVG(counts)
   OVER (PARTITION BY season
     ORDER BY year
     ROWS BETWEEN UNBOUNDED PRECEDING
         AND CURRENT ROW     -- 最初の行から現在行まで
     ) AS 累計の平均counts
FROM C_YEAR_MEDAL
ORDER BY season DESC, year DESC;

86_2

上記の結果から、SQL Serverと同様に、OVER句を使用することで、各行に対しての直近の数回や累計の合計などを抽出することができることが確認できました。

今日は以上まで

にほんブログ村 IT技術ブログへ
にほんブログ村

OVER句のROWS(SQL Server)

ITコーディネータのシュウです。

IMG_1284

2018年も、あっという間に3月の最後の週を迎えました。
ここしばらく、開発の案件が忙しく、ブログの原稿を作る時間が取れませんでした。
多少落ち着いてきたので、久しぶりに書いています。上の写真は、休みの日に息子と神奈川のほうに行く機会があり、桜が満開になっていたので写真を撮ってきました。やはり埼玉に比べると、少し神奈川のほうが暖かい気がしますし、桜も開花が早いですね!
久しぶりに長男と二人きりで電車に乗ったり、歩いたりして過ごしました。今度高校に入学しますが、いつの間にか成長している息子を見て、無事に育ってくれてとても感謝の気持ちが湧いてきました。これからいろいろとぶつかる壁や課題も出てくると思うけれど、頑張って乗り越えてほしいです。

それから、dbSheetClientの呉信用金庫様の事例がアップされています。
Excel I/Fの各種業務をdbSheetClientを使って、
圧倒的な処理スピードの向上を実現!(10分以上が瞬時に)
トップマネジメントを含めて全社員(約650名)が利用!
興味のある方は以下をご参照ください。
https://www.newcom07.jp/dbsheetclient/usrvoice/kure_shinkin.html

 <本日の題材>
OVER句のROWS(SQL Server)

以前、このブログでも「RANK, DENSE_RANK」という題目で、ランキング関数の中でOVER句を使った内容を題材として取り上げましたが、OVER句と一緒に使用する引数に、ROWS句というものがあり、行の計算対象を指定することができるという機能がありましたので、今回、それを取り上げてみます。これは、SQL Server 2012からの機能で、以下のような記述で範囲を指定します。

OVER (PARTITION BY 項目名1
     ORDER BY 項目名2
     ROWS BETWEEN A AND B
     )

上記の書き方で、項目名1毎にグループ化しながら、項目名2の並び順で、AからBの範囲内での抽出結果を表示することができます。(PARTITION BY句、ORDER BY句、ROWS句は必要なときのみ指定します)

このときの、A、Bの記述の仕方には、以下のようなものがあります。

CURRENT ROW
  --- 現在の行
n PRECEDING
  --- 現在の行からn行前
n FOLLOWING
  --- 現在の行から n 行後
UNBOUNDED PRECEDING
  --- パーティションの最初の行
UNBOUNDED FOLLOWING
  --- パーティションの最後の行

例)今回は、平昌オリンピックで日本中が盛り上がったことから、オリンピックで日本が取ったメダル数をデータにしたものを使用します。

テーブルは以下の定義:
CREATE TABLE DBO.メダル数(
季節  VARCHAR(4)
,年    DECIMAL(4)
,メダル色 VARCHAR(2)
,個数     INT
,CONSTRAINT pk_メダル数 PRIMARY KEY (季節,年,メダル色));

このテーブルに、夏季、冬季の日本が取ったメダル数を登録してみます。

INSERT INTO dbo.メダル数 VALUES('夏季',1912,'金',0);
INSERT INTO dbo.メダル数 VALUES('夏季',1912,'銀',0);
INSERT INTO dbo.メダル数 VALUES('夏季',1912,'銅',0);
 
INSERT INTO dbo.メダル数 VALUES('夏季',1920,'金',0);
INSERT INTO dbo.メダル数 VALUES('夏季',1920,'銀',2);
INSERT INTO dbo.メダル数 VALUES('夏季',1920,'銅',0);

--途中省略
INSERT INTO dbo.メダル数 VALUES('冬季',2014,'金',1);
INSERT INTO dbo.メダル数 VALUES('冬季',2014,'銀',4);
INSERT INTO dbo.メダル数 VALUES('冬季',2014,'銅',3);

INSERT INTO dbo.メダル数 VALUES('冬季',2018,'金',4);
INSERT INTO dbo.メダル数 VALUES('冬季',2018,'銀',5);
INSERT INTO dbo.メダル数 VALUES('冬季',2018,'銅',4);

夏季、冬季それぞれの、各年毎、メダル色毎のメダル数と、直近3回のメダル色毎の合計数、平均数を抽出し、年の新しい順に抽出してみます。

SELECT
  季節
,年
,メダル色
,個数
,SUM(個数)
    OVER (PARTITION BY 季節,メダル色
      ORDER BY 年
      ROWS BETWEEN 2 PRECEDING AND CURRENT ROW  
   -- 現在の行から2行前から現在行までの3行分
      ) AS 直近3回の合計個数
,AVG(個数)
    OVER (PARTITION BY 季節,メダル色
      ORDER BY 年
      ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
    -- 現在の行から2行前から現在行までの3行分
      ) AS 直近3回の平均個数
FROM dbo.メダル数
ORDER BY 季節,年 DESC,メダル色;

sql1

次に、金、銀、銅で色を分けずに、季節、年毎のメダル数の合計について、最初からの累計の合計個数と平均個数を抽出し、冬季、夏季の年の新しい順に表示してみます。

WITH C_YEAR_MEDAL(季節, 年, 個数) AS
(SELECT 季節, 年, SUM(個数)
    FROM dbo.メダル数
  GROUP BY 季節, 年
)
SELECT
  季節
 ,年
 ,個数
,SUM(個数)
      OVER (PARTITION BY 季節
           ORDER BY 年
           ROWS BETWEEN UNBOUNDED PRECEDING 
                           AND  CURRENT ROW
                           -- 最初の行から現在行まで
           ) AS 累計の合計個数
,AVG(個数)
       OVER (PARTITION BY 季節
           ORDER BY 年
           ROWS BETWEEN UNBOUNDED PRECEDING
                            AND CURRENT ROW
                           -- 最初の行から現在行まで
           ) AS 累計の平均個数
FROM C_YEAR_MEDAL
ORDER BY 季節 DESC, 年 DESC;

sql2_1
sql2_2

上記の結果から、OVER句 + ROWS句を使用することで、各行に対しての直近の数回や累計の合計などを抽出することができることが確認できました。

今日は以上まで

にほんブログ村 IT技術ブログへ
にほんブログ村

動的なデータマスキング(SQL Server 2016)

ITコーディネータのシュウです。

IMG_1132

2018年を迎えて、皆様如何お過ごしでしょうか? 本年もよろしくお願いいたします!

この1月は、非常に寒いという印象ですが、実際、先週の1/22には関東地方に大雪が降りました。「南岸低気圧」というのが原因とのことです。前日は晴れていて、天気予報が言うように、本当に次の日雪が降るのかな?と思っていたところ、見事に大雪となり、帰りは電車の遅延がひどく、普段1時間ちょっとで行けるところが、3時間以上かかって帰りました。それも、少し早めに帰宅したにもかかわらずです。
次の日は、朝早く起きて雪かきをしましたが、寒い日が続く中、しばらく雪が溶けずにアイスバーンのようになって、自転車や歩くのにもとても気を使いました。
この「南岸低気圧」、4年前にも関東に大雪を降らせたということですが、今後とも、この言葉に注意して行く必要があるようです。

それから、dbSheetClientのシャープ様の事例がアップされています。
Excel I/Fの新PSIシステムを構築!
各営業部門と生産企画部門における情報一元化を実現!
生産投入の精度向上と経営課題である在庫削減にも貢献!
約600名がシステムを利用、更に新PSIシステムは進化を継続中!
興味のある方は以下をご参照ください。
https://www.newcom07.jp/dbsheetclient/usrvoice/sharp.html


<本日の題材>
動的なデータマスキング(SQL Server 2016)

SQL Server 2016の新機能で、動的なデータマスキングの機能があるということで、ちょっとだけ試してみました。

動的データ マスク (DDM) は、特権のないユーザーに対して個人情報などデリケートなデータをマスクし、データの公開を制限するものです。DDMによって、クエリの結果にマスクルールが適用され、データを変更せずにマスキングすることができます。DDMを使用すると、アプリケーションのセキュリティの設計とコーディングを大幅に簡略化することができるということです。

それでは、簡単な例で確認してみます。
テーブル「顧客マスタ」を作成するときに、マスキングをかけたい列にマスクルールを設定しますが、次の4種類のマスクを利用できるようです。

・既定(default):指定のフィールドのデータ型に応じたフルマスク
 例えば文字列データ型 (char、 nchar、 varchar、 nvarchar、 text、 ntext) の場合は、XXXX またはそれ未満の数の X を使用。他にも、数値型や日付/時刻型にもそれぞれに対する設定あり。

・Email(email):メールアドレスの最初の 1 文字と定数サフィックスの ".com" をメールアドレスのフォームで公開するマスク方法。

・ランダム(random):ランダムマスク関数は任意の数字型に使用でき、指定した範囲内で生成したランダムな値でオリジナルの値をマスクします。

・カスタム文字列(partial):間にカスタム埋め込み文字列を追加し、最初と最後の文字を公開するマスク方法。
prefix,[padding],suffix

上記を使ってテーブルを作成します。

CREATE TABLE 顧客マスタ 
 (顧客NO varchar(7) PRIMARY KEY,
   氏名 nvarchar(100) MASKED WITH (FUNCTION = 'partial(1,"XXXXXXX",0)') NULL, 
  カナ nvarchar(100) MASKED WITH (FUNCTION = 'partial(0,"XXXXXXX",1)') NULL, 
  電話番号 varchar(13) MASKED WITH (FUNCTION = 'default()') NULL, 
  Eメール varchar(100) MASKED WITH (FUNCTION = 'email()') NULL,
   身長 numeric(4,1) MASKED WITH (FUNCTION = 'random(100, 200)'));

データを登録します。(架空のデータです)

insert into 顧客マスタ values('100001', '山田 昭男', 'ヤマダ アキオ', '03-1234-5678', 'a-yamada@abc.co.jp', 182);
insert into 顧客マスタ values('100345', '小林 栄治', 'コバヤシ エイジ', '080-9876-5431', 'eiji-koba@xyz.co.jp', 165);
insert into 顧客マスタ values('103025', '高橋 洋子', 'タカハシ ヨウコ', '06-0001-9999', 't-yoko@test.ne.jp', 152);

作成したユーザでデータをSELECTします。

Select * from 顧客マスタ;

select_1

上記のように通常通りの結果が抽出されます。

次に、顧客マスタに対してSELECT の権限だけを与えたユーザー「BlogUser」を作ります。

CREATE USER BlogUser WITHOUT LOGIN;

GRANT SELECT ON 顧客マスタ TO BlogUser;

cre_user

 この「BlogUser」で顧客マスタを検索したときに、動的データマスキングが有効になっていることを確認します。

EXECUTE AS USER = 'BlogUser';

SELECT * FROM dbo.顧客マスタ;

REVERT;

masking

抽出結果を見ると、以下のようにマスキングされていることが確認されました。

・氏名は頭1文字のみが正しい値で、残りは「X」でマスキング
・カナは、最後の1文字のみが正しい値で、残りは「X」でマスキング
・電話番号は、全て「xxxx」でマスキング
・Eメールは、最初の1文字が正しい値で、途中は「X」、最後は「.com」でマスキング
・身長は、100~200の間でランダムな値にマスキング

ちなみに、このユーザー「BlogUser」について、SQL Server Management Studioで確認すると、以下のように、顧客マスタへの「選択」の許可のみがあることが確認できます。

bloguser

今日は以上まで

にほんブログ村 IT技術ブログへ
にほんブログ村

照合順序(SQL Server)

ITコーディネータのシュウです。

IMG_1048

IMG_1061

ちょっと前に、出雲神話で有名な島根県に行く機会があり、時間があったので、たくさんの銅鐸が出土した加茂岩倉遺跡と、銅剣がたくさん出土した荒神谷遺跡を見に行って来ました。上の写真が加茂岩倉遺跡、下が荒神谷遺跡です。
もともと神話など、古代の歴史に興味があったこともあり、出雲には何かあるような気がして、この考古学上の歴史的な発見であった2つの遺跡に是非行ってみたかったので、とてもいい機会でした。
アマテラスの弟で出雲族の祖とされ、ヤマタノオロチ退治で有名なスサノオノミコト、イナバノ白ウサギで有名な国造りを行ったオオクニヌシノミコト、そして出雲の国譲りなどいろいろな話しが残されています。古代の日本において、邪馬台国がどこにあったのか、そして大和朝廷がどのようにつくられていったのか、いろいろな説がありますが、とても興味深い内容ですね。いつか、真実が明らかにされる日が来るのを楽しみにしたいと思います。

いよいよ、今年も残すところあとわずかになりました。いつの間にか年末になってしまったという感じです。今年も1年間いろいろとありがとうございました。なかなか忙しく、記事をアップする頻度がとても少なくなってしまいましたが、来年も頑張って記事を書ければと思っていますので、どうぞよろしくお願いいたします!

<本日の題材>
照合順序(SQL Server)

SQL Serverで、データの文字の大小関係を比較する場合の基準となるものを、照合順序(Collation)と呼んでいます。例えば、アルファベットの「a」「A」、かなの「あ」「ア」「ア」を小さいほうから順に並べたらどう並ぶか、漢字の「川」「皮」ではどちらが大きいのかなどの、文字の大小関係を決めているものになります。
様々なシステムでは、データを名前順に並べるとか、データが一致するものを検索するなどの処理が多々存在します。この照合順序が異なれば、クエリの結果が違ってきてしまうため、この文字の大小関係を決める照合順序というものはとても重要な要素になります。

SQL Serverの照合順序には、SQL照合順序とWindows照合順序の2種類があるとのことですが、SQL照合順序はUnicode データ型をサポートしていなかった SQL Server 6.5 以前のバージョンとの互換性のみを目的としている照合順序であるため、基本的に照合順序と言えば、Windows照合順序のことと考えればよいようです。

それでは、例をあげて照合順序について確認してみます。
あるデータベースの照合順序を確認してみると、「Japanese_CI_AS」となっていますが、他にも、CS、KS、WSなどのオプションがあります。例えば、「Japanese_90_CS_AS_KS_WS_SC」。

それぞれを簡単に説明すると、

・Japanese:辞書順に並び変えた場合の並び順が、日本語辞書順であることを表しています。ただし、ソート順の定義で、
Japanese, Japanese_XJIS, Japanese_Bushu_Kakusu, Japanese_Unicode
などの種類があります。

・90:照合順序のバージョンを表しています。 90 はバージョン 9.0 である SQL Server 2005、100 はバージョン 10.0 である SQL Server 2008 を表しています。

・CS:大文字と小文字を区別します。このオプションを設定すると、大文字より小文字が先に並べ替えられます。

・AS:濁音・半濁音・アクセントの有無を区別します。このオプションを選択しないと、濁音・半濁音・アクセントが区別されません。

・KS:ひらがなとカタカナを区別します。このオプションを選択しないと、ひらがなとカタカナは同じものと見なされます。

・WS:全角文字と半角文字を区別します。このオプションを選択しないと、同じ文字の全角表記と半角表記は同じものと見なされます。

・SC:SQL Server 2012 以降で、辞書順に並べる場合に補助文字を認識するかどうかを区別します。

また、並び順は、辞書順ではなくバイナリ順 (ビット配列順、文字コード順、コードポイント順) もあります。バイナリ順の照合順序の名前は、Japanese_90_BIN や Japanese_90_BIN2 のように CS_AS_KS_WS の部分が BIN または BIN2 となります。

「Japanese_CI_AS」となっているデータベースで具体的に試してみます。「大小比較」というテーブルを作成し、そこに、下記のようにデータを登録し、データを抽出してみます。

insert into dbo.大小比較(no, 文字) values(1,'あ');
insert into dbo.大小比較(no, 文字) values(2,'ア');
insert into dbo.大小比較(no, 文字) values(3,'ア');
insert into dbo.大小比較(no, 文字) values(4,'皮');
insert into dbo.大小比較(no, 文字) values(5,'川');
insert into dbo.大小比較(no, 文字) values(6,'革');
insert into dbo.大小比較(no, 文字) values(7,'大');
insert into dbo.大小比較(no, 文字) values(8,'題');
insert into dbo.大小比較(no, 文字) values(9,'1');
insert into dbo.大小比較(no, 文字) values(10,'1');
insert into dbo.大小比較(no, 文字) values(11,'a');
insert into dbo.大小比較(no, 文字) values(12,'A');

select * from dbo.大小比較
order by no;

select1

select * from dbo.大小比較
order by 文字;

select2

次に、条件として、「1」に等しいものを抽出してみます。

select * from dbo.大小比較
where文字 = '1'
order by 文字;

select3

全角と半角が同じものとして認識されているのが確認できます。
同様に、条件として、「あ」に等しいものを抽出してみます。

select * from dbo.大小比較
where文字 = 'あ'
order by 文字;

select4

ひらがなとカタカナが同じものとして認識されているのが確認できます。

上記の内容を区別するためには、オプションの部分を変更する必要があります。

ここで、このテーブルを含む「TEST」データベースの照合順序を変更してみます。

ALTER DATABASE TEST COLLATE Japanese_CI_AS_KS_WS;

select5

データベースの照合順序を変更した状態で、先ほどのSQLを実行してみます。

select6

何故か、結果は同じです。これは、データベースの照合順序を変更しても、既存のテーブルの照合順序は変更されないためで、下記のように項目について照合順序を設定してテーブルを変更する必要があります。

ALTER TABLE dbo.大小比較
ALTER COLUMN 文字 varchar(20)
COLLATE Japanese_CI_AS_KS_WS;

select7

この状態で、再度、前回行ったSQLを実行してみます。

select8

select9

全角と半角文字、ひらがなとカタカナが区別されて、それぞれ該当する1行のみが抽出されるようになりました。

今日は以上まで

にほんブログ村 IT技術ブログへ
にほんブログ村

データベースメール(SQL Server)

ITコーディネータのシュウです。

せんがたき

 少し前に、山梨県の昇仙峡に妻と行って来ました。写真は、仙娥滝(せんがたき)と呼ばれる滝で、昇仙峡のシンボルである覚円峰(かくえんぼう)の麓にあり、駐車場から徒歩5分くらいのところにあります。この滝は日本の滝百選にも選ばれていて、落差は30mあり、地殻変動による断層によって生じたものとのことです。

学生時代に一度昇仙峡に行った記憶があり、岩の上から下を見て、高いなあと思った記憶があったのですが、今回は、渓谷に沿って紅葉を見ながら妻と歩くことにしました。
秋晴れの中、たくさんの観光客が遊歩道を歩き、渓流や紅葉を楽しんでいました。カップルが皆手をつないで歩いていたので、私も妻と手をつなぎながら、久しぶりに夫婦で自然を満喫することができました。

<本日の題材>
データベースメール(SQL Server)

会社の同僚が、お客様のシステムで、SQL Serverのデータベースメールの機能を利用して、必要なタイミングでいろいろな情報をメールで知らせる仕組みを作ったということを聞き、今回はこれを題材にしてみます。ちなみに、確認したデータベースのバージョンは、SQL Server2014です。(データベースメールの機能は、SQL Server2012からのようです)

設定の方法ですが、SQL Server Management Studioを起動し、オブジェクトエクスプローラーの「管理」の中にある「データベースメール」を選択し、右クリックを押します。

設定1

そこで表示されるメニューの「データベースメールの構成」をクリックすると、以下のようなデータベースメール構成ウィザードが表示されますので、「次へ」をクリックします。

設定2

「構成タスクの選択」画面が出るので、「次のタスクを実行してデータベースメールをセットアップする」を選択した状態で、「次へ」ボタンを押下します。

設定3

すると、設定が初めての場合には、以下のようなメッセージが出ます。「データベースメール機能は使用できません。有効にしますか?」
ここで「はい」を選択します。

設定4

次に、「新しいプロファイル」設定画面が出てくるので、「プロファイル名」を設定した後、SMTPアカウントの「追加」ボタンをクリックします。

設定5

ここで、SMTPサーバーの設定を行います。

設定6

設定ができたら、「OK」ボタンを押下します。
(SMTP認証の設定が必要な場合は、その部分も設定します)

設定7

新しいプロファイルの画面に戻り、アカウントが追加されたているのを確認して、「次へ」ボタンをクリックします。

設定8

プロファイルセキュリティの管理の画面が出るので、確認してから「次へ」を押下します。

設定9

システムパラメータの構成の画面が出るので、こちらも確認して、「次へ」を押下します。このとき、禁止する添付ファイルの拡張子など、追加したい場合には、追加します。

設定10

ウィザードの完了画面が出るので、「完了」を押下すると、構成を実行します。

設定11

「成功」となれば、「閉じる」で終了します。
次に、メール送信のテストを行ってみます。

設定12

SQL Server Management Studioの「管理」の「データベースメール」を選択し、右クリックを押して、「テスト電子メールの送信」を押下します。

設定13

宛先を設定し、「テスト電子メールの送信」ボタンを押下します。

設定14

これによって、宛先のメールアドレスにメールが送付されることを確認します。

設定15

以上の手順で、SQL Serverのデータベースメールの設定とテストまで簡単にできました。

ただ、SQLを使用するアプリケーションの中で、このデータベースメールの仕組みを使ってSQLの結果などをメールで送付したいというのが目的だったので、SQLのプロシージャを使ってこのデータベースメールを送ってみます。

システムで用意しているプロシージャ「sp_send_dbmail」を使って、下記のようなSQL文を作成して実行してみます。

--メール送信
EXEC msdb.dbo.sp_send_dbmail
  @profile_name = 'メール送付'
,@recipients = 'testuser@newcomblog.jp'
,@subject = '処理完了通知'
,@body = 'データベースメールテスト。'
,@query = 'SELECT * FROM BLOG.dbo.DEPT'
,@attach_query_result_as_file = 1
;

設定16

ここで、@querry 変数にSQL文を指定すると、メールにSQLの結果を付けることができます。(このとき、テーブルはデータベース名から指定します)
また、@attach_query_result_as_file = 1 と指定することで SQL の結果を添付ファイルにして送ることができます。

宛先のメールアドレスに上記の内容のメールが届けば成功です。

設定17

添付ファイルの中身を見ると以下のようになっています。

設定18

データベースメールの仕組みを使って、SQLの結果をメールで送付できることが確認できました。

今日は以上まで

 

 

 

にほんブログ村 IT技術ブログへ
にほんブログ村

Management Studioでのデータ編集

ITコーディネータのシュウです。

IMG_0896

お久しぶりです。あっという間に10月の後半に入ってきました。最近急に寒くなってきましたが、お元気でお過ごしでしょうか?
しばらく開発の仕事がとても忙しく、ブログを書こうと思いながら、ずるずると時が経ってしまいました。申し訳ありません。

この間、いろいろなことがありましたが、大きく記憶に残っていることとして、高校野球で、なんと埼玉の花咲徳栄高校が埼玉県勢として初めて夏の高校野球での優勝旗を持ち帰ったことです。
実は、花咲徳栄高校は結構自宅から近いのと、知人のお子さんでも結構そこに通っているので、とても親近感が湧くのですが、まさか優勝するとは思っていませんでした。
投手2枚看板と打線も毎試合2桁安打で、とても強かったですね。嬉しい限りです。

また、国際情勢が緊迫してきている中、衆議院が解散されて、もうすぐ選挙ですね。高校3年生になって18歳の誕生日を迎えた3番目の娘も、選挙権があるということでカードが送られてきたので、初めての選挙に行くと張り切っていました。こういう時、子供が育つのは早いなと、つくづく思わされます。

それから、事例がまたアップされています。
dbSheetClientで内製化を実現
土木・建築業務における各種システムを構築し、データは統合DBに格納!
情報システム部と設計本部がシステム開発・管理を主導!ということで、株式会社鴻池組様の事例です。
興味のある方は以下をご参照ください。
http://www.newcom07.jp/dbsheetclient/usrvoice/konoike_construction.html

<本日の題材>
Management Studioの使い方(SQL Server)

SQL Serverで、テーブルのデータを変更したいが、いちいちupdate文を書くのが面倒なとき、あるいは時間に余裕がないときに、ツールで簡単に変更できたらいいと思うことがよくありますよね。
SQL Server のManagement Studioというツールをデータの確認などでよく使用しますが、そこでは、テーブルを右クリックすると、「上位200行の編集」という機能があって、行が少ないときはそれで目的のデータの変更ができますが、テーブルの行数が多い場合には、目的のデータを一覧から探すのが面倒なので、そこでの変更はあきらめてしまうことも多いと思います。
それでいい方法がないかと調べてみたところ、Management Studioでうまくできるということなので、それを試してみたいと思います。

SQL Server Management Studioを起動し、データを変更したいデータベースのテーブルにカーソルを合わせた後、マウスの右クリックで表示されるメニューの「上位200行の編集(E)」を選択すると、データの編集ができることはご存知だと思います。

ManS_データ編集

その後、以下のようなデータの編集画面が表示されますが、

ManS_編集画面

ここで、さらに、メニューの「クエリーデザイナー」で表示される「ペイン」、さらに「SQL」を選択すると、下記のようなウィンドウが表示されます。

ManS_pain

この上側のSQLのところに、今回編集したいデータを絞るための条件を追加してみます。今回は「拠点」が「シカゴ」の社員データのみを変更したいので、「WHERE 拠点=’シカゴ’」を入れて、再度SQLを実行します。

ManS_pain_実行

すると、「拠点」が「シカゴ」の社員データのみが結果に表示され、データ編集も可能になるので、そこで値の変更を行います。

ManS_変更実施

こうすることで、行数が多い場合でも、条件を指定して絞ることで、Management Studioの「上位 n 行の編集」でデータの変更をすることができます。

なお、そもそも「上位200行の編集」となっているのを、もっと多い行数に変更することも可能です。

メニューの「ツール」>「オプション」>「SQL Server オブジェクト エクスプローラー」を選択すると、下記のような画面が出てきますので、「上位 <n> 行の編集コマンドの値」を「200」からもっと多い値に変更すればよいです。

ManS_上位n行編集

 
今日は以上まで

にほんブログ村 IT技術ブログへ
にほんブログ村