たにーの闘争

日々の気になる事を書いていきます

「クエリプロセッサが内部リソースを使い果たしクエリプランを作成できませんでした」の対処方法

概要

The query processor ran out of internal resources and could not produce a query plan. This is a rare event and only expected for extremely complex queries or queries that reference a very large number of tables or partitions. Please simplify the query. If you believe you have received this message in error, contact Customer Support Services for more information.

結論

このエラーが出力された原因のクエリを簡略化するしかない。

原因

こんなSQL書いてた(悪い例)
(連携件数によっては、サブクエリがめちゃめちゃ長くなる仕組み)

select 
  Entertainment_a.id
 ,Entertainment_a.NAME
 ,Entertainment_a.CATEGORY
 ,Entertainment_a.TITLE
from
 Entertainment Entertainment_a
where
 Entertainment_a.NAME='山田' AND Entertainment_a.CATEGORY='映画'
 and
 not exists 
 (select 
   Entertainment_b.id 
  from 
   Entertainment Entertainment_b
  where
   Entertainment_a.id = Entertainment_b.id
  AND
    (
     -- 件数が何件だろうがサブクエリにぶち込んでいく
      (Entertainment_b.NAME='山田' AND Entertainment_b.CATEGORY='映画' AND Entertainment_b.TITLE='パラサイト')
   or (Entertainment_b.NAME='山田' AND Entertainment_b.CATEGORY='映画' AND Entertainment_b.TITLE='のび太の結婚前夜')
   or (Entertainment_b.NAME='山田' AND Entertainment_b.CATEGORY='映画' AND Entertainment_b.TITLE='愛しのアイリーン')
   or (Entertainment_b.NAME='山田' AND Entertainment_b.CATEGORY='映画' AND Entertainment_b.TITLE='ランボー')
    )
  )
  

C#

using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.SqlClient;
using System.Text;
using FavoriteMovies.Dto;

namespace FavoriteMovies.Common.DB
{
    /// <summary>
    /// 各種コード取得クラス
    /// </summary>
    public static class SearchMovies
    {
        /// <summary>
        /// 検索
        /// </summary>
        /// <param name="connection">接続情報</param>
        /// <param name="movies">新規データ</param>
        /// <returns>MovieDto</returns>
        public static List<MovieDto> Get(DbConnection connection, List<MovieDto> movies)
        {
            List<MovieDto> retVal = new List<MovieDto>();

            StringBuilder sql = new StringBuilder();
            sql.Append($" SELECT");
            sql.Append($" Entertainment_a.id");
            sql.Append($" ,Entertainment_a.NAME");
            sql.Append($" ,Entertainment_a.CATEGORY");
            sql.Append($" ,Entertainment_a.TITLE");
            sql.Append($" ,Entertainment_a.YEAR");
            sql.Append($" ,Entertainment_a.COUNTRY");
            sql.Append($" FROM");
            sql.Append($" Entertainment Entertainment_a");
            sql.Append($" WHERE");
            sql.Append($" Entertainment_a.NAME = '{movies[0].NAME}' 
            AND Entertainment_a.CATEGORY = '{movies[0].CATEGORY}' 
            AND Entertainment_a.PHY_DLE_FLG <> '1'");
            sql.Append($" AND");
            sql.Append($" NOT EXISTS");
            sql.Append($" (SELECT");
            sql.Append($" Entertainment_b.id");
            sql.Append($" FROM");
            sql.Append($" Entertainment Entertainment_b");
            sql.Append($" WHERE");
            sql.Append($" Entertainment_a.id = 
            Entertainment_b.id");
            sql.Append($" AND(");
            sql.Append($" 
            (Entertainment_b.NAME='{movies[0].NAME}' 
            AND Entertainment_b.CATEGORY='{movies[0].CATEGORY}' 
            AND Entertainment_b.TITLE='{movies[0].TITLE}')");
            //ここでパラメータの値を条件式にセットしていく
            for (int i = 1; i < movies.Count; i++)
            {
                sql.Append($" OR (
                    Entertainment_b.NAME='{movies[i].NAME}' 
                AND Entertainment_b.CATEGORY='{movies[i].CATEGORY}' 
                AND Entertainment_b.TITLE='{movies[i].TITLE}')");
            }
            sql.Append($" ))");

            using (DbCommand command = connection.CreateCommand())
            {
                try
                {
                    command.Connection = connection;
                    command.Connection.Open();
                    command.CommandText = sql.ToString();
                    command.Prepare();

                    DbDataReader reader = command.ExecuteReader();
                    while (reader.Read())
                    {
                        MovieDto movie = new MovieDto();

                        movie.CATEGORY = reader["CATEGORY"].ToString();
                        movie.NAME = reader["NAME"].ToString();
                        movie.TITLE = reader["TITLE"].ToString();
                        movie.YEAR = reader["YEAR"].ToString();
                        movie.COUNTRY = Convert.ToDecimal(reader["COUNTRY"]);
                        movie.PHY_DLE_FLG = "1";
                        retVal.Add(movie);
                    }
                }
                finally
                {
                    command.Connection.Close();
                }
            }
            return retVal;
        }
    }
}