【Salesforce】 System.QueryException: Non-selective query against large object type (more than 200000 rows).

【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.

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です