LoginSignup
4
4

More than 5 years have passed since last update.

kintone でSQLを使う(その2)パフォーマンス検証

Last updated at Posted at 2017-02-15

kintone でSQLを使う の続き。
対象レコードを通常使われる程度に増やして、パフォーマンス検証してみました。

結果は、レコード取得がほとんどの処理時間で、集計・表示は問題なし。

集計元アプリ 

それなりに数値の件数があるものということで、市区町村別人口データを使います。

2017-02-15_12h16_06.png

集計結果

2017-02-15_12h19_22.png

必要ライブラリ

集計コード

処理概要

  • 人口情報アプリのレコードを取得
  • json 構造を簡単化
  • SQL で集計(Group By)
  • ログ処理
////////////////////////////////////////////////////////////////////////////
// kintone JavaScript: Summary of kintone records by alasql.
//  2017.02.15 by rex0220
////////////////////////////////////////////////////////////////////////////
(function() {
    "use strict";

    // Log Output
    var Log = (function() {
        // コンストラクタ
        var Log = function(name, enabled) {
            if(!(this instanceof Log)) {
                return new Log(name);
            }
            this.name = name || 'log';
            this.enabled = enabled;
            this.start  = moment();
            this.prev = this.start;
            this.sno = 1;
            if (!this.enabled) return;
            console.log(this.name + ' start: ' + this.start.format('YYYY-MM-DD HH:mm:ss'));
        }

        var p = Log.prototype;

        // writeメソッド
        p.write = function(step, info) {
            if (!this.enabled) return;
            var m1 = moment();
            var d1 = m1.diff(this.prev, 'sss') / 1000;
            if (info)
                console.log(this.name + '-' + this.sno + ' ' + m1.format('HH:mm:ss')  + ' (' + d1 + ' 秒) : ' + step + ', ', info );
            else
                console.log(this.name + '-' + this.sno + ' ' + m1.format('HH:mm:ss')  + ' (' + d1 + ' 秒) : ' + step );
            this.prev = m1;
            this.sno++;
        }

        // infoメソッド
        p.info = function(step, info) {
            if (!this.enabled) return;
            console.log(this.name + '-' + this.sno + ' ' + step, info );
        }

        // endメソッド
        p.end = function() {
            if (!this.enabled) return;
            var m1 = moment();
            var d1 = m1.diff(this.start, 'sss') / 1000;
            console.log(this.name + ' end  : ' + m1.format('YYYY-MM-DD HH:mm:ss')  + ' (' + d1 + ' 秒)' );
        }

        return Log;
    })();


    // 一覧表示
    kintone.events.on("app.record.index.show", function(event) {
        if (event.viewId !== 5332655) return event;

        var log = new Log('SQL-CHECK', true);

        var obj = {};

        // 人口情報取得
        fetchRecords(event.appId, '市など区分 in ("1","2","3")', ['都道府県コード', '都道府県名', '総数', '総数_男', '総数_女']).then(function(records) {

            log.write('get record', records.length + ' records.' );

            obj.rs1 = convertToRows(records);

            log.write('convert rows', obj.rs1.length + ' rows.' );


            // 顧客情報と注文情報を集計
            var result1 = 
                alasql(
                "SELECT a.[都道府県コード], a.[都道府県名], SUM(a.[総数]) as [総数], SUM(a.[総数_男]) as [総数_男], SUM(a.[総数_女]) as [総数_女] \
                FROM ? AS a \
                GROUP BY a.[都道府県コード], a.[都道府県名] \
                ORDER BY a.[都道府県コード], a.[都道府県名]", [obj.rs1]);

            log.write('select group by', result1.length + ' rows.' );

            // grid 表示
            var grid = document.getElementById('xp-grid');
            new Handsontable(grid, { 
                data: result1, 
                colWidths: [50, 100, 200, 200, 200],
                colHeaders: ['都道府県コード', '都道府県名', '総数', '総数_男', '総数_女'], 
                columns: [
                    { data: '都道府県コード' },
                    { data: '都道府県名' },
                    { data: '総数', type: 'numeric', format: '0,0' },
                    { data: '総数_男', type: 'numeric', format: '0,0' },
                    { data: '総数_女', type: 'numeric', format: '0,0' },
                ],
                readOnly: true 
            });

            log.write('grid display ');
            log.end();

        });

        return event;
    });


    // get records
    function fetchRecords(appId, opt_query, opt_fields, opt_offset, opt_limit, opt_records) {
        var query = opt_query || '';
        var offset = opt_offset || 0;
        var limit = opt_limit || 500;
        var allRecords = opt_records || [];
        var params = {app: appId, query: query + ' limit ' + limit + ' offset ' + offset };
        if (opt_fields) params.fields = opt_fields;
        return kintone.api(kintone.api.url('/k/v1/records', true), 'GET', params).then(function(resp) {
            allRecords = allRecords.concat(resp.records);
            if (resp.records.length === limit) {
                return fetchRecords(appId, query, opt_fields, offset + limit, limit, allRecords);
            }
            return allRecords;
        });
    }

    // records convert to table rows 
    function convertToRows(records) {
        var rows = records.map(function(record){
            var keys = Object.keys(record);
            var row = {};
            keys.map(function(key){
                row[key] = record[key].type === 'NUMBER' ? Number(record[key].value) : record[key].value;
            });
            return row;
        });
        return rows;
    }

})();

実行時間

約5秒の処理時間のほとんどがレコード取得にかかっており、SQL 処理は問題ない。

SQL-CHECK start: 2017-02-15 13:59:20
SQL-CHECK-1 13:59:24 (4.568 秒) : get record,  1719 records.
SQL-CHECK-2 13:59:24 (0.007 秒) : convert rows,  1719 rows.
SQL-CHECK-3 13:59:24 (0.03 秒) : select group by,  47 rows.
SQL-CHECK-4 13:59:24 (0.067 秒) : grid display 
SQL-CHECK end  : 2017-02-15 13:59:24 (4.673 秒)

対象レコードの抽出条件を変えて、件数を絞った場合。
約1,000 件のデータで、約3秒。この程度なら、運用でも問題ないと思われる。

SQL-CHECK start: 2017-02-15 14:08:16
SQL-CHECK-1 14:08:19 (2.832 秒) : get record,  1058 records.
SQL-CHECK-2 14:08:19 (0.005 秒) : convert rows,  1058 rows.
SQL-CHECK-3 14:08:19 (0.035 秒) : select group by,  25 rows.
SQL-CHECK-4 14:08:19 (0.062 秒) : grid display 
SQL-CHECK end  : 2017-02-15 14:08:19 (2.934 秒)

あとがき

SQL 実行のパフォーマンスについては、kintone の 1,000 レコード程度なら問題なし。
複数アプリのレコードを Join するしくみなどでも、レコード取得の処理が課題になる。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4