いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

DevExpress奮闘記-004 TreeListに対してのデータバインディング時の速度差 (TreeList, DataSource, DataSet, BindingSource)

通常のWindows FormsのTreeViewには、DataSourceを利用したデータバインディングがありませんがDevExpressの方の
TreeListにはDataSourceプロパティがあります。なので、よくDataSourceを指定したデータバインディングを行う事が
多いのですが、このときに指定するオブジェクトにはちょっととしたTipsがあります。


何かというと、DataSourceに指定するオブジェクトがDataTableもしくはDataSetの場合、このTreeList、何故かしらないですが
遅くなります。で、BindingSource経由で指定するととても速いです。
尚、この速度差は大量のデータを含んだデータソースの場合に発生します。(たとえば2万件とか)
100件とか200件の場合は気にならない程度の差です。


どれくらいの速度差が出るかというと、私の環境(Intel Xeon 2GHz, 4G RAM)の場合で以下のような感じです。


[2万レコード存在するデータセットを指定した場合のデータバインディングに掛かった時間]

DataSetを直接指定 : 約5.6秒
BindingSourceを指定: 約0.03秒


マシンによって差があると思いますが、大体同じような差が出ると思います。


なので、結論としては

TreeListにてBoundModeで利用する際はBindingSourceをデータソースとして指定する事。

となります。


んで、確認用に作ったサンプルもったいないのであげときます。
必要なDLLはEXEと同じディレクトリにおいてあるのでDevExpressが入っていないマシンでも
動作するはずです。尚、データベース接続も使ってません。


アプリが起動したら、件数を入力して"Create Test Data"ボタンを押下して、その後Reloadボタンを
押下してみてください。各種の読み込みに掛かった時間が表示されます。

DataSetを直接指定した場合のTreeListについては、すごく時間が掛かる場合があるのでデフォルト
でEnabled=falseにしてます。チェックボックスをONにすると計測されるようになります。


フォームのソースコードはこんな感じ。

using System;
using System.Data;
using System.Diagnostics;
using System.Windows.Forms;

namespace Gsf.Demo {

    public partial class MainForm : DevExpress.XtraEditors.XtraForm {

        public MainForm() {
            InitializeComponent();
        }

        private void MainForm_Load(object sender, EventArgs e) {

            txtOutputDataCount.Text = "200";

            StartPosition = FormStartPosition.CenterScreen;
            ActiveControl = txtOutputDataCount;
        }

        private void btnCreateTestData_Click(object sender, EventArgs e) {
            
            Enabled = false;
            Application.DoEvents();

            if(cmpValidationProvider.Validate()){

                DataSet ds = new DataSet("Persons");
                DataTable table = ds.Tables.Add();

                table.TableName = "Person";

                table.Columns.Add("Id", typeof(int));
                table.Columns.Add("Name");
                table.Columns.Add("Age", typeof(int));
                table.Columns.Add("Address");

                for (int i = 0; i < int.Parse(txtOutputDataCount.Text); i++) {
                    DataRow r = table.NewRow();
                    r.ItemArray = new object[] { i, "gsf_zero" + i.ToString(), 28 + i, "address" + i.ToString() };
                    table.Rows.Add(r);
                }

                ds.WriteXml("TestData.xml");
                sttMainStatus.Caption = "Data Created.";
            }
            
            Enabled = true;
        }

        private void chkEnableTree1_CheckedChanged(object sender, EventArgs e) {
            trlPersons.Enabled = chkEnableTree1.Checked;
        }
       
        private void btnReload_Click(object sender, EventArgs e) {
            ReloadData();
        }

        protected void ReloadData() {
            Stopwatch formLoadingWatch = new Stopwatch();
            formLoadingWatch.Reset();
            formLoadingWatch.Start();

            Stopwatch w = new Stopwatch();
            w.Start();
            DataSet ds = new DataSet();
            ds.ReadXml("TestData.xml");
            w.Stop();

            lblLoadDataSet.Text = string.Format("Data Set Loading={0}", w.Elapsed.ToString());
            lblDataCount.Text = string.Format("Data Count={0}", ds.Tables[0].Rows.Count);

            //
            // DevExpressのTreeListはデータテーブルもしくはデータセットをそのままバインディング
            // すると凄く遅い。一旦、BindingSourceなどに移し変えるとぐっと早くなる。
            //
            // trlPersonsはDataSetを直接バインディング.
            // trlPersons2はBindingSource経由でバインディング
            //
            if(trlPersons.Enabled){
                w.Reset();
                w.Start();
                trlPersons.BeginUpdate();
                trlPersons.DataSource = ds;
                trlPersons.DataMember = "Person";
                trlPersons.EndUpdate();
                w.Stop();
                lciTree1.Text = w.Elapsed.ToString();
            }

            BindingSource dataSource = new BindingSource(ds, "Person");
            w.Reset();
            w.Start();
            trlPersons2.BeginUpdate();
            trlPersons2.DataSource = dataSource;
            trlPersons2.EndUpdate();
            w.Stop();
            lciTree2.Text = w.Elapsed.ToString();

            //
            // GridControlの場合は、データセットを直接バインディングしても速度的には
            // 大差ない。
            //
            w.Reset();
            w.Start();
            grdPersons.BeginUpdate();
            grdPersons.DataSource = ds;
            grdPersons.DataMember = "Person";
            grdPersons.EndUpdate();
            w.Stop();
            lciGrid1.Text = w.Elapsed.ToString();

            w.Reset();
            w.Start();
            grdPersons2.BeginUpdate();
            grdPersons2.DataSource = dataSource;
            grdPersons2.EndUpdate();
            w.Stop();
            lciGrid2.Text = w.Elapsed.ToString();

            formLoadingWatch.Stop();
            lblFormLoading.Text = string.Format("Form Loading={0}", formLoadingWatch.Elapsed.ToString());

            sttMainStatus.Caption = "Reload Complete.";
        }

    }

}


[サンプルアプリ]

[DevExpressのバージョン]

  • v8.1.3.0