Salesforce技術ブログ:DMLのstatementsとrowsの数え方について考えてみる

Salesforce技術ブログ:DMLのstatementsとrowsの数え方について考えてみる

Salesforce技術ブログ:DMLのstatementsとrowsの数え方について考えてみる

ハロー、ハリーくめです
今回はナレッジではなくApex開発の基礎のお話。

開発者の皆さん、DMLに詳しいですか?
認定資格の勉強をしてるときとかによく出てきて、開発時には回数にかなり気を遣う存在ですよね。
初めて勉強する方は特にそうなんですけども、
DMLのstatementsは簡単に数えられるけど、rowsっていったい何件なのかわかりにくいってなりませんか?
今回はそれぞれどうなるのか検証してみました。

DMLには何があるの

これらがDMLにカウントされるメソッド一覧です。
・Approval.process
・Database.convertLead
・Database.emptyRecycleBin
・Database.rollback
・Database.setSavePoint
・System.runAs
・Database.merge/merge
・Database.delete/delete
・Database.insert/insert
・Database.update/update
・Database.upsert/upsert
・Database.undelete/undelete

statementsとrowsって何だ

statements:DMLにカウントされるメソッドが実行される回数のこと
rows:DMLによって処理されたレコードの行数のこと

 
//取引先の作成
Account acc1 = new Account(name = 'ヨツユビハリネズミ');
Account acc2 = new Account(name = 'ヨーロッパハリネズミ');
List<Account> accounts = new List<Account>{acc1,acc2};

Insert accounts;

System.SavePoint sp = Database.setSavepoint();

//削除用取引先の取得
List<Account> forDeletes = [SELECT Id FROM Account Where Name LIKE '%ハリネズミ'];
List<Id> accIds = new List<Id>();
for(Account del:forDeletes){
     accIds.add(del.Id);
}

//当該取引先の完全削除
Delete forDeletes;
Database.emptyRecycleBin(accIds);

Database.rollback(sp);
 

上記のソースを実行すると、
statements:5
rows:8
になります。
どうしてそうなるのでしょうか?

statementsとrowsを楽に確認する

今実行しているソース内でDMLがいくつ実行されているのかは
「Limits Class」を利用すると簡単に知ることができます。
※合計だけであればLimits Classなしで確認可能です。
これを利用して、先ほどのDMLの実行の様子を確認していこうと思います。

 
//取引先の作成
Account acc1 = new Account(name = 'モリハリネズミ');
Account acc2 = new Account(name = 'オオミミハリネズミ');
List<Account> accounts = new List<Account>{acc1,acc2};

Insert accounts;
System.debug('Insert accounts');
System.debug(limits.getDMLStatements());
System.debug(limits.getDMLRows());

System.SavePoint sp = Database.setSavepoint();
System.debug('Database.setSavePoint');
System.debug(limits.getDMLStatements());
System.debug(limits.getDMLRows());

//削除用取引先の取得
List<Account> forDeletes = [SELECT Id FROM Account Where Name LIKE '%ハリネズミ'];
List<Id> accIds = new List<Id>();
for(Account del:forDeletes){
     accIds.add(del.Id);
}

//当該取引先の完全削除
Delete forDeletes;
System.debug('Delete forDeletes');
System.debug(limits.getDMLStatements());
System.debug(limits.getDMLRows());

Database.emptyRecycleBin(accIds);
System.debug('emptyRecycleBin');
System.debug(limits.getDMLStatements());
System.debug(limits.getDMLRows());

Database.rollback(sp);
System.debug('Database.rollback');
System.debug(limits.getDMLStatements());
System.debug(limits.getDMLRows());
 

実行ログはこちら。
※DEBUGに記載している(+1)といった文字は後から追記したものです。

 
36.0 APEX_CODE,DEBUG;APEX_PROFILING,INFO;CALLOUT,INFO;DB,INFO;SYSTEM,DEBUG;VALIDATION,INFO;VISUALFORCE,DEBUG;WAVE,INFO;WORKFLOW,INFO
17:51:33.6 (6616133)|USER_INFO|[EXTERNAL]|0057F000000lHHd|m-kume+weblog@n-sysdes.co.jp|日本標準時|GMT+09:00
17:51:33.6 (6636606)|EXECUTION_STARTED
17:51:33.6 (6640229)|CODE_UNIT_STARTED|[EXTERNAL]|execute_anonymous_apex
17:51:33.6 (7394817)|DML_BEGIN|[6]|Op:Insert|Type:Account|Rows:2
17:51:33.6 (50623738)|DML_END|[6]
17:51:33.6 (50726392)|USER_DEBUG|[7]|DEBUG|Insert accounts
17:51:33.6 (50764473)|USER_DEBUG|[8]|DEBUG|1
17:51:33.6 (50777569)|USER_DEBUG|[9]|DEBUG|2
17:51:33.6 (51021574)|SAVEPOINT_SET|[11]|SavepointValue0
17:51:33.6 (51055294)|USER_DEBUG|[12]|DEBUG|Database.setSavePoint
17:51:33.6 (51070088)|USER_DEBUG|[13]|DEBUG|2 (+1)
17:51:33.6 (51080937)|USER_DEBUG|[14]|DEBUG|3 (+1)
17:51:33.6 (51241590)|SOQL_EXECUTE_BEGIN|[17]|Aggregations:0|SELECT Id FROM Account WHERE Name LIKE '%ハリネズミ'
17:51:33.6 (58481054)|SOQL_EXECUTE_END|[17]|Rows:2
17:51:33.6 (58829788)|DML_BEGIN|[24]|Op:Delete|Type:Account|Rows:2
17:51:33.6 (130324137)|DML_END|[24]
17:51:33.6 (130423985)|USER_DEBUG|[25]|DEBUG|Delete forDeletes
17:51:33.6 (130459007)|USER_DEBUG|[26]|DEBUG|3 (+1)
17:51:33.6 (130472536)|USER_DEBUG|[27]|DEBUG|5 (+2)
17:51:33.6 (130573103)|DML_BEGIN|[29]|Op:emptyRecycleBin|Type:Id|Rows:2
17:51:33.6 (135686208)|DML_END|[29]
17:51:33.6 (135712400)|USER_DEBUG|[30]|DEBUG|emptyRecycleBin
17:51:33.6 (135734054)|USER_DEBUG|[31]|DEBUG|4 (+1)
17:51:33.6 (135746285)|USER_DEBUG|[32]|DEBUG|7 (+2)
17:51:33.6 (135802173)|SAVEPOINT_ROLLBACK|[34]|SavepointValue0
17:51:33.6 (137568492)|USER_DEBUG|[35]|DEBUG|Database.rollback
17:51:33.6 (137589737)|USER_DEBUG|[36]|DEBUG|5 (+1)
17:51:33.6 (137600852)|USER_DEBUG|[37]|DEBUG|8 (+1)
17:51:33.150 (150888841)|CUMULATIVE_LIMIT_USAGE
17:51:33.150 (150888841)|LIMIT_USAGE_FOR_NS|(default)|
Number of SOQL queries: 1 out of 100
Number of query rows: 2 out of 50000
Number of SOSL queries: 0 out of 20
Number of DML statements: 5 out of 150
Number of DML rows: 8 out of 10000
Maximum CPU time: 0 out of 10000
Maximum heap size: 0 out of 6000000
Number of callouts: 0 out of 100
Number of Email Invocations: 0 out of 10
Number of future calls: 0 out of 50
Number of queueable jobs added to the queue: 0 out of 50
Number of Mobile Apex push calls: 0 out of 10
17:51:33.150 (150888841)|CUMULATIVE_LIMIT_USAGE_END
17:51:33.6 (150940698)|CODE_UNIT_FINISHED|execute_anonymous_apex
17:51:33.6 (151723627)|EXECUTION_FINISHED
 

いわずもがなレコードを処理するメソッドはそのレコード数がカウントされています。
savePointやrollback自体はオブジェクトレコードの処理をしているように見えませんが rows として1カウントされています。

rowsの原則

レコードを処理するメソッド(Insert、Deleteなど)は処理したレコード数を計算します。
しかし、レコードを処理せず状態を変更するもの(SavePoint、rollbackなど)は、それ自体を rows=1 として計算されます。

また rollback で処理が savePoint の時点まで戻ったとしても、
戻る前に実行したDMLはなかったことにならずきちんと計算されているので、勘違いされていた方もいるかもしれませんね。

検証していないメソッドはありますが、rows の算出はこの原則に従いますので、気になる方は一度検証してみてください。

では、また次回。

简体中文English日本語한국어
翻訳