programing

Contains()를 사용할 때 2100 매개 변수 제한(SQL Server)을 초과하는 경우

minimums 2023. 7. 12. 23:39
반응형

Contains()를 사용할 때 2100 매개 변수 제한(SQL Server)을 초과하는 경우

from f in CUSTOMERS
where depts.Contains(f.DEPT_ID)
select f.NAME

depts목록입니다(IEnumerable<int>부서 ID의 )

이 쿼리는 큰 목록(예: 약 3000개의 디프티 ID)을 통과할 때까지 잘 작동합니다.그러면 다음 오류가 발생합니다.

수신 TDS(Table Data Stream) 원격 프로시저 호출(RPC) 프로토콜 스트림이 잘못되었습니다.이 RPC 요청에 너무 많은 매개 변수가 제공되었습니다.최대 2100입니다.

쿼리를 다음으로 변경했습니다.

var dept_ids = string.Join(" ", depts.ToStringArray());
from f in CUSTOMERS
where dept_ids.IndexOf(Convert.ToString(f.DEPT_id)) != -1
select f.NAME

사용.IndexOf()오류를 수정했지만 쿼리가 느려졌습니다.이것을 해결할 다른 방법이 있습니까?정말 감사합니다.

나의 해결책(Guids필터링 기준으로 사용할 ID 목록입니다.):

List<MyTestEntity> result = new List<MyTestEntity>();
for(int i = 0; i < Math.Ceiling((double)Guids.Count / 2000); i++)
{
    var nextGuids = Guids.Skip(i * 2000).Take(2000);
    result.AddRange(db.Tests.Where(x => nextGuids.Contains(x.Id)));
}
this.DataContext = result;

쿼리를 sql에 작성하고 엔티티를 첨부하는 것이 어떻습니까?

Linq에서 일한 지 오래되었지만, 다음과 같습니다.

IQuery q = Session.CreateQuery(@"
         select * 
         from customerTable f
         where f.DEPT_id in (" + string.Join(",", depts.ToStringArray()) + ")");
q.AttachEntity(CUSTOMER);

물론 주사를 맞지 않도록 보호해야겠지만, 그렇게 어렵지는 않을 겁니다.

LINQKit 프로젝트에는 이 문제를 해결하기 위해 이러한 문을 일괄 처리하는 기술이 있기 때문에 따라 LINQKit 프로젝트를 확인할 수 있습니다.저는 Predicate Builder를 사용하여 로컬 컬렉션을 더 작은 덩어리로 나누는 것이 아이디어라고 생각하지만, 저는 이 문제를 처리하는 더 자연스러운 방법을 찾고 있었기 때문에 솔루션을 자세히 검토하지 않았습니다.

안타깝게도 이 동작을 수정하라는 제 제안에 대한 Microsoft의 답변을 보면 .NET Framework 4.0 또는 이후 서비스 팩에 대해 이 문제를 해결하도록 설정된 계획이 없습니다.

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=475984

업데이트:

저는 이것이 LINQ to SQL에 대해 수정될 것인지 아니면 MSDN 포럼의 ADO.NET Entity Framework에 대해 수정될 것인지에 대한 논의를 시작했습니다.이러한 주제에 대한 자세한 내용과 XML 및 SQL UDF를 사용하여 해결한 임시 해결 방법은 다음 게시물을 참조하십시오.

저도 비슷한 문제가 있었고, 두 가지 방법으로 해결할 수 있었습니다.

  1. 교차법
  2. 신분증으로 가입.

목록에 없는 값을 가져오기 위해 Except 메서드 또는 Left Join을 사용했습니다.

갱신하다

EntityFramework 6.2는 다음 쿼리를 성공적으로 실행합니다.

var employeeIDs = Enumerable.Range(3, 5000);
var orders =
    from order in Orders
    where employeeIDs.Contains((int)order.EmployeeID)
    select order;

당신의 게시물은 조금 전의 것이었지만, 아마도 누군가가 이것으로부터 이익을 얻을 것입니다.Entity Framework는 사용자가 다른 매개 변수 수를 보낼 때마다 캐시에 추가되는 많은 쿼리 캐싱을 수행합니다."포함" 호출을 사용하면 SQL에서 "WHERE x IN(@p1, @p2....@pn)"과 같은 절을 생성하고 EF 캐시를 블롯합니다.

최근에 저는 이것을 다루는 새로운 방법을 찾았고, 당신이 전체 데이터 테이블을 매개 변수로 만들 수 있다는 것을 발견했습니다.방법은 다음과 같습니다.

먼저 사용자 정의 테이블 유형을 만들어야 하므로 SQL Server에서 이를 실행합니다(사용자 정의 유형을 "TableId"라고 불렀습니다).

        CREATE TYPE [dbo].[TableId] AS TABLE(
            Id[int] PRIMARY KEY
        )

그런 다음 C#에서 데이터 테이블을 생성하여 유형과 일치하는 구조화된 매개 변수로 로드할 수 있습니다.원하는 만큼 데이터 행을 추가할 수 있습니다.

        DataTable dt = new DataTable();
        dt.Columns.Add("id", typeof(int));

이것은 검색할 임의의 ID 목록입니다.목록을 원하는 만큼 크게 만들 수 있습니다.

        dt.Rows.Add(24262);
        dt.Rows.Add(24267);
        dt.Rows.Add(24264);

사용자 지정 테이블 유형과 데이터 테이블을 사용하여 SqlParameter를 만듭니다.

        SqlParameter tableParameter = new SqlParameter("@id", SqlDbType.Structured);
        tableParameter.TypeName = "dbo.TableId";
        tableParameter.Value = dt;

그런 다음 기존 테이블을 조인하는 컨텍스트에서 테이블 매개 변수의 값으로 SQL을 호출할 수 있습니다.이렇게 하면 ID 목록과 일치하는 모든 레코드가 제공됩니다.

        var items = context.Dailies.FromSqlRaw<Dailies>("SELECT * FROM dbo.Dailies d INNER JOIN @id id ON d.Daily_ID = id.id", tableParameter).AsNoTracking().ToList();

Linq에서 생성된 IN 문에 매개 변수로 전달하기 전에 항상 디프 목록을 더 작은 집합으로 분할할 수 있습니다.다음을 참조:

큰 IEnumberable을 항목 고정량의 작은 IEnumberable로 나눕니다.

언급URL : https://stackoverflow.com/questions/656167/hitting-the-2100-parameter-limit-sql-server-when-using-contains

반응형