rex0220 計算式プラグイン テーブル処理時間の改善

計算式プラグインで、テーブル内項目で計算式を指定するとテーブル行数が多いと処理時間が問題になるケースがあります。
その原因調査と対策を検討してみます。

# 概要

[rex0220 計算式プラグイン テーブル内小計](https://qiita.com/rex0220/items/63808fc1b0d3ff9cd561)をテーブル行数を１００行で検証
操作：分類を「明細」から「概要」に変更

|  | 処理時間(秒) |対策 |
|:-:|:-:|:-|
|改善前| 25  |   |
|対策１   | 45(+20)  |テーブル内項目の計算式から集計関数を無くす  |
|対策２   | 4(-21)  |プラグインの計算処理を非同期化し、無駄なイベント処理をスキップ  |
|対策３   | 2(-23)  |対策１＋対策２。集計関数を無くしプラグインの計算処理を非同期化  |


- 改善前：　約25秒
![2023-04-16_14h33_44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/4eca2d20-b649-003c-2ab0-45ce408a1b3d.png)

- 対策１：テーブル内項目の計算式から集計関数を無くす
    - 約45秒（+20秒 悪化）
    - 集計関数の代わりにテーブルに項目を追加して、行単位の累計処理に変更
    - 集計関数の処理時間が減ったが、値変更イベントが増加し、結果的に処理時間増加

![2023-04-16_14h42_48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/597e4350-556f-1063-cb1b-98aa526c9055.png)

- 対策２：プラグインの計算処理を非同期化し、無駄なイベント処理をスキップ
    - 約4秒（-21秒 改善）
    - 計算式プラグイン Ver.62 以降の「非同期計算」（ベータ版機能）指定

![2023-04-16_15h08_08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/1f4f7bec-e7dc-329e-b71c-020f4b5034f9.png)

- 対策３：集計関数を無くし、プラグインの計算処理を非同期化し、無駄なイベント処理をスキップ
    - 約2秒（-23秒 改善）

# 処理時間の調査
とりあえず地道に何に時間がかかっているか調べます。

- コードに処理時刻のログ追加
![2023-04-16_15h14_25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/6abf418e-98a8-6406-1146-d7b29c978d1a.png)

- 処理時間の測定
![2023-04-16_15h13_44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/10f41fc9-ec63-76c6-b4e5-f6a36b9d8f6e.png)

# 主にかかっている処理時間

- テーブル内項目で集計関数を実行すると、秒単位で時間がかかる
    - 集計関数：　テーブル全行をループ処理で計算
    - 金額の計算；LASTIF, SUMIF が集計関数を指定
```.JS
LET(CNO,ROWNO(テーブル),
  SWITCH(分類,
    "明細",数量*単価,
    "小計",LET(PNO,NVL(LASTIF(AND(ROWNO(テーブル)<CNO,分類="小計"),ROWNO(テーブル)),-1),
      SUMIF(AND(ROWNO(テーブル)<CNO,ROWNO(テーブル)>PNO,分類="明細"),金額)),
    "")
)
```
- 値変更イベントが多い
    - 計算結果を他項目の計算で指定すると、値変更イベントで再計算する
    - 数量、単価、金額の値変更イベントで再計算
※計算処理で設定した値によって、値変更イベントが発生するため、再計算しても結果は変わらない


# 対策１
テーブル内項目の集計関数の代わりに、セット累計金額を追加し累計処理に変更
![2023-04-16_15h55_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/657d3f0b-fe05-e728-38e2-65fdb888add1.png)

```改善前.js
// 金額
LET(CNO,ROWNO(テーブル),
  SWITCH(分類,
    "明細",数量*単価,
    "小計",LET(PNO,NVL(LASTIF(AND(ROWNO(テーブル)<CNO,分類="小計"),ROWNO(テーブル)),-1),
      SUMIF(AND(ROWNO(テーブル)<CNO,ROWNO(テーブル)>PNO,分類="明細"),金額)),
    "")
)
```
```対策１.js
// 金額
SWITCH(分類,
  "明細",数量*単価,
  "小計",NVL(SUBTABLE(セット累計金額,ROWNO(テーブル)-1),0),
  "")
// セット累計金額
LET(w,NVL(SUBTABLE(セット累計金額,ROWNO(テーブル)-1),0),
SWITCH(分類,
  "明細",TR_SUM(金額,w),
  "小計",w,
  "")
)
```

- 対策案１の影響
    - 値変更イベント処理の増加：　結果的に処理時間が増加
    - 追加項目の非表示処理
セット累計金額を非表示に指定してもテーブル行表示が完了するまで、イベント処理が実行されないため、セット累計金額がしばらく表示される。
※項目非表示プラグインを適用で、テーブル行表示完了前もセット累計金額を非表示にできます。

[項目非表示プラグイン](https://qiita.com/rex0220/items/67d560779c9d879f67f6)の設定
![2023-04-16_16h07_07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/c93f7ec1-64a0-835b-0143-429e62f708a2.png)

# 対策２

プラグインの計算処理を非同期化し、無駄なイベント処理をスキップ
※計算式プラグイン Ver.62 以降（ベータ版機能）

![2023-04-16_15h08_08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100572/b3fe0f81-9be1-6114-7195-e060866530b8.png)

- 対策案２の影響
    - 計算処理のタイミングが変わる
        - 従来：　項目の値変更の計算処理後に、カーソル移動
        - 非同期：　項目の値変更でカーソル移動後に計算処理
    - 他プラグイン等のイベント処理との競合
        - 処理タイミングが変わることにより、他プラグイン等へ影響が考えられます。

# 対策３

対策１と対策２を適用することで処理時間を削減できますが、影響も同様に発生します。

# まとめ

テーブル行数が多い場合は、対策２の非同期計算を実施することで、処理時間を改善できそうです。
ただし他プラグイン等への影響を検証する必要があります。
実用的には、対策３の方が使いやすいと思いますが、項目追加などの手間が必要ですので、要件に合わせて検討。