「遅いGAS」はRange一括操作でほぼ解決できる
GASでスプレッドシートを操作し始めると、
最初は問題なく動いていた処理が、データ量の増加とともに急激に遅くなることがあります。
その原因の多くは、「1セルずつ操作している」ことです。
GAS011で学んだ getValue / setValue は理解しやすい反面、
行数が増えるとすぐに限界が見えてきます。
この記事では、GAS高速化の第一歩となる
Range(範囲)の一括操作について解説します。
getValues・setValues を正しく使えるようになると、
GASの処理時間は体感で数十倍改善することも珍しくありません。
目次
なぜ1セル操作は遅くなるのか
GASで1回 getValue / setValue を実行するたびに、
内部では「GAS ⇔ スプレッドシート間の通信」が発生しています。
- GASからリクエスト送信
- スプレッドシート側で処理
- 結果をGASに返却
この通信をループ内で何百回・何千回も行うと、
それだけで処理時間が大きく伸びてしまいます。
Range一括操作では、この通信を最小限の回数に抑えられるため、
大幅な高速化が可能になります。
Range一括操作の基本概念
Range一括操作とは、
複数セルをまとめて配列として扱う考え方です。
複数セルを取得すると、GASでは
2次元配列として値が返ってきます。
const values = sheet.getRange(1, 1, 3, 2).getValues();
上記コードの戻り値は、次のような構造になります。
[
[A1, B1],
[A2, B2],
[A3, B3]
]
「行 → 列」の順で並んでいる点が重要です。
getValuesでまとめて取得する
getValuesを使えば、複数セルを一度に取得できます。
const range = sheet.getRange(1, 1, 100, 3);
const values = range.getValues();
取得後は、JavaScriptの配列として自由に加工できます。
values.forEach(row => {
const status = row[0]; // A列
const amount = row[1]; // B列
});
列番号は 0始まり になる点に注意してください。
setValuesでまとめて書き込む
setValuesは、getValuesと必ずセットで使うメソッドです。
sheet.getRange(1, 1, values.length, values[0].length)
.setValues(values);
setValuesに渡す配列は、
Rangeと完全に同じ行数・列数である必要があります。
1セルでもズレるとエラーになるため、
配列サイズの管理は非常に重要です。
配列構造の理解(2次元配列)
Range一括操作でつまずきやすいポイントが、
2次元配列の扱いです。
アクセス方法は次の形になります。
values[行インデックス][列インデックス]
たとえば、2行目B列の値は次のように取得します。
const value = values[1][1];
よくある失敗と注意点
- setValuesの配列サイズが合っていない
- 1次元配列を渡してしまう
- 空配列をsetValuesしてしまう
特に、0行の配列は setValues できません。
実務では、必ず行数チェックを行います。
if (values.length === 0) {
return;
}
PropertiesService+try-catchで安全に一括操作する
Range一括操作は高速ですが、
設定ミスがあると大量のセルを一気に壊すリスクもあります。
そのため実務では、次の2点を必ず組み合わせます。
- PropertiesServiceによる設定値管理
- try-catchによる例外処理
設定値を取得する
function getSheetSettings() {
const props = PropertiesService.getScriptProperties();
const spreadsheetId = props.getProperty('SPREADSHEET_ID');
const sheetName = props.getProperty('SHEET_NAME');
if (!spreadsheetId) {
throw new Error('SPREADSHEET_ID が未設定です');
}
if (!sheetName) {
throw new Error('SHEET_NAME が未設定です');
}
return { spreadsheetId, sheetName };
}
try-catch付き一括更新例
function updateStatusBulkSafe() {
try {
const { spreadsheetId, sheetName } = getSheetSettings();
const ss = SpreadsheetApp.openById(spreadsheetId);
const sheet = ss.getSheetByName(sheetName);
if (!sheet) {
throw new Error('シートが存在しません:' + sheetName);
}
const range = sheet.getRange(1, 1, 1000, 1);
const values = range.getValues();
let updated = false;
for (let i = 0; i < values.length; i++) {
if (values[i][0] === '') {
values[i][0] = '完了';
updated = true;
}
}
if (updated) {
range.setValues(values);
Logger.log('一括更新完了');
}
} catch (e) {
Logger.log('エラー発生:' + e.message);
}
}
実務での改善パターン例
遅い例(1セルずつ)
for (let i = 1; i <= 1000; i++) {
const cell = sheet.getRange(i, 1);
if (cell.getValue() === '') {
cell.setValue('完了');
}
}
改善例(Range一括操作)
const range = sheet.getRange(1, 1, 1000, 1);
const values = range.getValues();
for (let i = 0; i < values.length; i++) {
if (values[i][0] === '') {
values[i][0] = '完了';
}
}
range.setValues(values);
まとめ
この記事では、GASでRangeを一括操作する方法として、
getValues・setValuesの基本から、実務向けの安全設計までを解説しました。
Range一括操作は、GAS高速化の最重要スキルです。
次回は、シート自体を操作する方法(追加・削除・コピー)を解説します。
0 件のコメント:
コメントを投稿