サービス業で働く社内SEのブログ

技術メモを適当にかいつまんで記載します

【C#】ReactivePropertyをModelで使う場合の留意点

ReactivePropertyはViewModelで使われている事が多い気がしていました。
そこでModelでもバンバン使っちゃって良いのでは...と思っていたところ、管理者の@okazukiさんからアドバイスいただきました。

デフォルトでUIスレッドですが、ISchedulerを引数にするオーバーロードがあるので、指定することもできるみたいです。

【C#】ReactivePropertyのReactiveCollectionについて

ここのところ、せこせこReactivePropertyを勉強中なのでそのメモを記載します。
※RPの詳細は当該ライブラリ管理者のかずきさんブログを参考にするのが一番です。 blog.okazuki.jp

UIコントロールにObservableCollectionをバインドしていた場合当該コレクションに対してUIスレッド以外から要素の操作をすると例外を吐きます。
が、ObservableCollectionを継承しているReactivePropertyReactiveCollectionを用いると、同じような使い方でUIスレッドで要素の操作が可能になります。
コンストラクタでUIスレッド以外も指定できそうです。

namespace DiffBetweenObservableCollectionAndReactiveCollection
{
    class MainWindowViewModel
    {
        public ReactiveCollection<string> reactiveCollection { get; private set; }
        public ObservableCollection<string> observableCollection { get; private set; }

        public MainWindowViewModel()
        {
            observableCollection = new ObservableCollection<string>();
            reactiveCollection = new ReactiveCollection<string>();
        }

        public void AddObservableCollection()
        {
            Task.Run(() =>
            {
                for (int i = 0; i < 10; i++)
                {
                    this.observableCollection.Add(i.ToString());
                }
            });
        }

        public void AddReactiveCollection()
        {
            Task.Run(() =>
            {
                for (int i = 0; i < 10; i++)
                {
                    this.reactiveCollection.AddOnScheduler(i.ToString());
                }
            });
        }

    }
}

上記のようにViewModelにバインドしているObservableCollectionにAddするとNotSupportedExceptionをはきますが、ReactiveCollectionAddOnSchedulerを使用すれば楽にUIスレッド以外から要素の追加ができました。
Githubにも上げました。

github.com

【Xamarin】Xamarin.FormsでMySQLに直接接続する

とても需要がなさそうなタイトルですね。

要はクラサバです。
通常であればApp⇔WebAPI⇔DBとやる流れのところを
App⇔DBの直繋ぎでやってしまおうという試みです。

この手法自体は一般的に見れば悪手です。
というより絶対にやるべきではありません。
しかしながら、社内の業務システムにおいて、比較的小規模かつPrivateな環境であれば
わざわざWebAPIを立てるのもコストになる為、そういう時には直繋ぎでやってしまっても良いのではないかということで試してみました。

開発環境は以下の通りです。
Windows10Pro
VisualStudio2015Community
Xamarin.Forms4.0
MySQL5.6
また私自身がXamarinAccountiOSしか持っていませんので
ソリューション作成直後にAndroid(WPも)プロジェクトは速攻削除しています。
恐らくどれでも動く気もするのですが検証はしておりません。

プロジェクト作成

まずは新規でXamarin.Forms Sharedプロジェクトを作成します。
f:id:Einherjar1632:20151122162359p:plain
Xamarin.Forms Portableもありますが、複数の環境で扱える特性上Sharedと比べ使用できる.NET Frameworkが限定されます。
MySQLへの接続はSystem.Data名前空間へのアクセスが必須になりますのでこちらを選択下さい。

各種dllを参照させる

下記から取得しましょう。
MySQL Plugin / Components / Xamarin
解凍しlib\ios\MySql.Data.CF.dlliOSのプロジェクトに参照させます。
その際、System.DataI18N.Westアセンブリも参照させましょう。
謎の後者については後述しますがバグ回避用です。
f:id:Einherjar1632:20151122221859p:plain

実装コード

Sharedプロジェクトに以下Forms Xaml Pageを追加します。
f:id:Einherjar1632:20151122222454p:plain
f:id:Einherjar1632:20151122222657p:plain

xamlには以下を記述し

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamarinFormsMySQL.XamarinFormsMySQLPage">
    <Label Text="{Binding MainText}" VerticalOptions="Center" HorizontalOptions="Center" />

  <StackLayout Padding="10,0">
    <Label x:Name="LblMsg" Text="MySQL" VerticalOptions="CenterAndExpand" HorizontalOptions="Center" />
    <Button x:Name="BtnConnect" Clicked="OnButtonClicked" FontSize="24" Text="XamarinMySQLTest" VerticalOptions="CenterAndExpand" HorizontalOptions="Center" />
  </StackLayout>
  
</ContentPage>

コードビハインドに以下を記述します。
謎のおまじないnew CP1250();がありますが、バグ回避のためです。
MySQLdllで設定されている文字セットはデフォルトでCP1250ですが、Xamarinだと何故か認識できないみたいです。

using System;
using MySql.Data.MySqlClient;
using Xamarin.Forms;
using I18N.West;

namespace XamarinFormsMySQL
{
    public partial class XamarinFormsMySQLPage : ContentPage
    {
        public XamarinFormsMySQLPage ()
        {
            InitializeComponent ();
        }

        public void OnButtonClicked(object sender, EventArgs args)
        {
            try
            {
                new CP1250();
                var cs = string.Format("Server=YourIPAddress;Port=3306;database=YourDatabase;User Id=YourID;Password=YourPassword;charset=utf8");
                using(var db = new MySqlConnection(cs))
                {
                    db.Open();
                    var queryString = "select hello from helloxamarin";
                    var sqlcmd = new MySqlCommand(queryString, db);
                    var result = sqlcmd.ExecuteScalar().ToString();
                    LblMsg.Text = result;
                    db.Close();
                }
            }
            catch (Exception ex)
            {
                LblMsg.Text = ex.ToString();
            }
        }

    }
}

あとはApp.csから追加したxamlを呼ぶようにして終わりです。

using Xamarin.Forms;

namespace XamarinFormsMySQL
{
    public class App : Application
    {
        public App ()
        {
            MainPage = new XamarinFormsMySQLPage();
        }
    }
}

デバッグしてみる

MySQLには予めtestスキーマを作りhelloカラムを持ったhelloxamarinテーブルを作成しておきました。
helloカラムの中身はHelloXamarinMySQLです。

f:id:Einherjar1632:20151122225201p:plain
比較的お手軽簡単にいきましたね。
あと私の環境ですと、何故かアイコンがビルド時にコピーできないようでビルドエラーが出ましたので、iOSプロジェクトのResourcesフォルダの画像は削除しました。
以下、Githubにも上げてあります。
github.com

【AWS】Windows環境でオンプレVMをAWSのEC2にインポート(移行)する

元ネタはクラメソさんのこれです。

dev.classmethod.jp

クラメソさんのだとEC2 API Toolの利用がMacからだったので
Windows環境だとどうするかのメモ的なものになります。

といってもやる事は殆ど変わっていません。
仮想マシンをOVF形式でエクスポートするところまでは一緒ですので
・vmdkファイルはある前提です。
・S3のバケットも作っておいて下さい。
・EC2 API Toolは以下の「Download the Amazon EC2 API Tools」から落とせます。
Amazon EC2 API Tools : Developer Tools : Amazon Web Services

おもむろにcmdを開きましてToolsのパスを設定

PATH=C:\Program Files\Amazon\ec2-api-tools-1.7.5.1\bin\


EC2_HOMEとJAVA_HOMEの設定(しないと後々出てくるec2-import-instanceで怒られる)

SET EC2_HOME=C:\Program Files\Amazon\ec2-api-tools-1.7.5.1
SET JAVA_HOME=C:\Program Files\Java\jdk1.7.0_51


S3へのアクセスキーとシークレットキーを設定

SET AWS_ACCESS_KEY=アクセスキー
SET AWS_SECRET_KEY=シークレットキー


リージョンの設定(以下はアジアパシフィック東京)

SET EC2_URL=https://ec2.ap-northeast-1.amazonaws.com


プロキシの設定

SET EC2_JVM_ARGS=-Dhttp.proxySet=true -Dhttps.proxySet=true -Dhttp.proxyHost=XX.XX.XX.XX -Dhttp.proxyPort=XX -Dhttps.proxyHost=XX.XX.XX.XX -Dhttps.proxyPort=XX


で、以下のコマンドでvmdkファイルからEC2作成

ec2-import-instance C:\disk1.vmdk -f VMDK -t t2.micro -a i386 -b einherjar1632-bucket -o アクセスキー -w シークレットキー -p Linux --subnet subnet-XXXXXXXX --private-ip-address XX.XX.XX.XX -z ap-northeast-1a

-t:EC2のインスタンスタイプを設定
-a:32bitOSなら「i386」を、64bitOSなら「x86_64」を設定
-b:S3のバケットを設定
-p:Windows環境の場合は「Windows」にして下さい。
--subnet:EC2に指定するサブネットを設定
--private-ip-address:EC2に適用するIPを設定


以下コマンドを実行し、Completeとなってたら出来ていると思います。

ec2-describe-conversion-tasks

S3にアップされてからEC2化するまで暫く時間がかかるので、定期的に実行して確認すると良いです。
無事EC2ができたらS3の中身は邪魔ですので消しておきましょう。

【Oracle】ダイレクトパスリード (Direct Path Read) について

ダイレクトパスリードとはバッファキャッシュを経由しないSELECTの事。
この事から直接ストレージからデータを引っ張ってくるため
当然ながらDBサーバのI/Oは高くなります。

これはパラレルクエリを使用した場合になりやすく
またチューニング・速度改善の観点としてパラレルクエリで小さいテーブルを処理させる場合は
バッファキャッシュ上に十分データをキャッシュする事も出来るため
かえって遅くなる事もあります。

逆に大規模なテーブルに対してのパラレルクエリは
そもそもバッファキャッシュキープ出来きない事が懸念される(キャッシュできるデータ量を超えている事が多いため)ため
I/Oを発生させてでもパラレル化し
ダイレクトパスリードさせる事をおすすめします。

尚、パラレルクエリのバッファキャッシュキープが出来ない件ですが
Oracle11gからは、インメモリパラレルクエリ(In-Memory Parallel Query)の設定が出来るため
パラレルでもバッファキャッシュを用いる事が出来ます。
ただしインメモリパラレルクエリには注意点があって
この機能を有効化する場合は
・自動パラレル度決定
・パラレルキューイング
も同時に設定されてしまいます。
特にチューニング・速度改善の観点からはパラレルキューイングが厄介で
要するにSQLが発行されたタイミングで十分なパラレルサーバが無い場合はキューに入れられて
条件が満たされた時にはじめてデキューされる事(このタイミングで処理される)
により返って遅くなってしまう場合もあります。

【Oracle】遅いSQLを特定するSQL

ブログの移設ついでに過去のブログ内容を投稿。

DBAであればOEMでSQL監視から特定してみたり
AWRレポートを発行したり等でどのSQLボトルネックになっているかを調査する事が出来ますが
開発者サイドに立った場合になかなかこういったところまで踏み込む事は難しいと思います。
そもそもちゃんとした会社であれば実装部隊とチューニング部隊とが分かれている(と聞かされている)ため
携わる機会すら無いかもしれません。

そういった場合を考慮しSQL1発で取得出来るクエリを作成しました。

SELECT
    DISTINCT S.SID
  , S.STATUS
  , S.PROGRAM
  , q.MODULE
  , q.SQL_ID
  , dbms_lob.substr(q.SQL_FULLTEXT,3000,1 ) SQL
  , s.LAST_CALL_ET 実行時間
  , q.PARSING_SCHEMA_NAME
  , q.FIRST_LOAD_TIME
  , q.LAST_LOAD_TIME
  , s.OSUSER
  , S.MACHINE
FROM
    v$session s
  , v$sql q
WHERE
    s.SQL_ID = q.SQL_ID
--↓ここの数字を変えます。このサンプルでは10秒以上実行され続けているSQLを特定
AND s.LAST_CALL_ET > 10
--↑ここの数字を変えます。このサンプルでは10秒以上実行され続けているSQLを特定
AND q.PARSING_SCHEMA_NAME <> 'SYSMAN'
--↓使用する開発環境ソフトウェアは除外すると見やすいかも
AND NOT q.MODULE IN ('cse.exe','osqledit.exe','ob10.exe')
--↑使用する開発環境ソフトウェアは除外すると見やすいかも
AND S.STATUS = 'ACTIVE'
ORDER BY
    1


V$SESSIONとV$SQLへの参照が必要ですので、
これらは必要なロールを付与する等で対応して下さい。

上記のサンプルでは10秒以上実行され続けているSQLを特定します。
私は開発環境ソフトウェアに関して
CSE
・ObjectBrowser
・OSqlEdit
を使い分けて使用していますので
これらから発行されたSQLは対象として引っかからないように除外してあります。

このSQLは現在実行されているものにスポットが当たりますので
例えば監視アプリやバッチ等で何分かおきに発行するように組み込む事により
実行に時間がかかっているSQLの特定が可能となります。
これで後は該当SQLの実行計画を見るなりして
速度改善・パフォーマンスチューニングに繋げれます。