【Salesforce】 System.QueryException: Non-selective query against large object type (more than 200000 rows).
Salesforceで既に動いているシステムにて、エラーが発生しました。
caused by: System.QueryException: Non-selective query against large object type (more than 200000 rows). Consider an indexed filter or contact salesforce.com about custom indexing.
久しぶりに見たエラーです。
トリガ内でSOQLを発行した際に起きるやつですね。
大量のレコードに対してSOQLを発行する際にINDEX項目を使用したフィルタリングをしない場合に発生します。
https://help.salesforce.com/articleView?id=000176875&language=ja&type=1
効率的なクエリを書きましょうということですね。
https://trailhead.salesforce.com/ja/content/learn/modules/database_basics_dotnet/writing_efficient_queries
https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/langCon_apex_SOQL_VLSQ.htm
今回の場合はあるレコードを1件だけ、取得するSOQLでした。
こんな感じです。
List<Account> accountList; // レコードを取得する accountList = [ select Id, Name, AccountIndex__c from Account order by CreatedDate limit 1];
Where句がありませんね。
CreatedDateにはINDEXが付けられているということなので、ちょこっと修正しておきました。
List<Account> accountList; Date limitDate; // 1年分を取得 limitDate = Date.today().addYears(-1); // レコードを取得する accountList = [ select Id, Name, AccountIndex__c from Account where CreatedDate >= :limitDate order by CreatedDate limit 1];
これで一安心と思ったのですが、そんなことはありませんでした。
件数としては20万レコードを下回るのに、同じエラーが発生したのです。
上のURLに、このように書かれていました。
つまり、SOQL の実行結果が 200,000 レコード未満であったとしても、実行計画が SOQL の効率を確認した結果、非効率なクエリであると判断した際に Non-selective query against large object type (more than 100000 rows) というエラーが出力されます。
非効率な場合はダメとのことです。
もしくは、テキスト項目の比較演算子はダメとのことなので、日付も同じ扱いだった可能性もあります。
比較演算子でなければ良いのでしょうか。
たとえば、こんな感じです。
List<Account> accountList; // レコードを取得する accountList = [ select Id, Name, AccountIndex__c from Account where CreatedDate = THIS_MONTH or CreatedDate = LAST_MONTH order by CreatedDate limit 1];
比較演算子を使っていないのですが、どうでしょうか。
Sandboxで大量レコードを作成することは出来ないため、確認が出来ませんでした。
そのため、実際にはカウンタ用のレコードを作成し、それに従って取得するように修正しました。
List<Counter__c> counterList; List<Account> accountList; Counter__c counter; // カウンタレコードを取得する counterList = [ select Id, Name, Count__c from Counter__c limit 1]; // カウンタレコードが存在しない場合は作成する if(counterList.isEmpty()){ counterList.add(new Counter__c()); counterList[0].Count__c = 1; } // レコードを取得する counter = counterList[0]; // レコードを取得する accountList = [ select Id, Name, AccountIndex__c from Account where AccountIndex__c = :counter.Count__c limit 1]; /* レコードが増える際にカウントアップ */
レコードを1件のみ取得し、AccountIndex__cを指定しているのでエラーは発生しなくなりました。
SOQLの修正のみで解決できるとカッコよかったんですけどね。。
開発者コンソールでクエリ実行プランツールというものがあるようです。
その機能でクエリを評価してくれるようなので、今回の修正を検討する際に少し遊んでしまいました。
No comments.