4

16ms-30ms에서 실행되는 다음 쿼리가 있습니다.해시가 포함 된 인덱싱 된 열에서 cfqueryparam으로 검색이 느림

<cfquery name="local.test1" datasource="imagecdn"> 
    SELECT hash FROM jobs WHERE hash in(
     'EBDA95630915EB80709C69089315399B', 
     '3617B8E6CF0C62ECBD3C48DDF8585466', 
     'D519A38F09FDA868A2FEF1C55C9FEE76', 
     '135F94C3774F7719CFF8FF3A275D2D05', 
     'D58FAE69C559273D8427673A08193789', 
     '2BD7276F209768F2FCA6635659D7922A', 
     'B1E3CFBFCCFF6F5B48A849A050E6D424', 
     '2288F5B8A797F5302E8CA24323617236', 
     '8951883E36B5D38A4643DFAA0396BF13', 
     '839210BD564E30BE1355D1A6D4EF7081', 
     'ED4A2CB0C28B608C29576819CF7BE19B', 
     'CB26925A4874945B810707D5FF0B91F2', 
     '33B2FC229F0CC797A02AD163CDBA0875', 
     '624986E7547DBAC0F47B3005CFDE0A16', 
     '6F692C289BD805CEE41EF59F83F16F4D', 
     '8551F0033C617BD9EADAAD6CEC4B3E9E', 
     '94C3C0A74C2DE085FF9F1BBF928821A4', 
     '28DC1A9D2A69C2EDF5E6C0E6368A0B3C' 
    ) 
</cfquery> 

동일한 쿼리를 실행하지만 cfqueryparam을 사용하면 500ms ~ 2000ms에서 실행됩니다.

<cfset local.hashes = "[list of the same ids as above]"> 
<cfquery name="local.test2" datasource="imagecdn"> 
    SELECT hash FROM jobs WHERE hash in(
     <cfqueryparam cfsqltype="cf_sql_varchar" value="#local.hashes#" list="yes"> 
    ) 
</cfquery> 

표에는 약 60,000 개의 행이 있습니다. "해시"열은 varchar (50)이며 클러스터되지 않은 고유 한 인덱스가 있지만 기본 키는 아닙니다. DB 서버는 MSSQL 2008입니다. 웹 서버는 최신 버전의 CF9를 실행하고 있습니다.

cfqueryparam으로 인해 성능이 폭격하는 이유는 무엇입니까? 페이지를 새로 고침 한 횟수에 상관없이 매번이 방식으로 작동합니다. 목록을 2 ~ 3 개의 해시만으로 페어링하면 150 ~ 200 밀리 초일 때 성능이 떨어집니다. cfqueryparam을 제거하면 성능이 예상대로 유지됩니다. 이 상황에서는 SQL 주입 가능성이 있으므로 cfqueryparam을 사용하는 것이 좋습니다. 그러나 인덱스 된 열에서 2 개의 레코드를 찾으려면 100ms가 걸리지 않아야합니다.

편집 : 우리는 hash() UUID가 아닌 나 GUIDS에 의해 생성 된 해시를 사용하는

  1. . 해시는 이미지에서 실행할 작업 집합에 대한 계획이 포함 된 hash(SerializeJSON({ struct }))에 의해 생성됩니다. 이것의 목적은 우리가 삽입 전에 그리고 그 구조에 대한 정확한 유일한 ID를 찾기 전에 알 수있게 해준다. 이 해시는 이미 DB에 저장된 구조의 "색인"역할을합니다. 또한 해시와 동일한 구조가 동일한 결과에 해시됩니다 (UUIDS 및 GUID에는 해당되지 않음).

  2. 쿼리가 5 개의 다른 CF9 서버에서 실행되고 있으며 모두 동일한 동작을 나타냅니다. 나에게 이것은 CF9가 뭔가를 캐싱한다는 생각을 배제한다. 모든 서버가 똑같은 DB에 연결되므로 캐싱이 발생하면 DB 수준이어야합니다.

+3

varchar 대신 cf_sql_char를 사용해 보셨습니까? MSSQL이 배열을 면밀히 살펴보고 더 나은 실행 계획을 제공하도록 강요 할 수 있습니다. 분명히 캐시에서 나오는 계획은 실시간으로 컴파일하는 계획만큼 효율적이지 않습니다. 또한 인덱스 힌트를 추가하십시오. 개발 분석기로 추적 분석기를 실행하면 실행 계획에 몇 가지 단서를 줄 수 있습니다. 그게 전부예요 :) –

+1

목록에 대한 prepare 문을 다시 사용할 수 없기 때문에 매번 다시 컴파일됩니다. 왜냐하면 SQL 삽입을 방지하기 위해 자신의 논리를 사용하는 것이 확실하면 cfqueryparam을 건너 뛰는 것이 적합 할 수 있습니다. 이것 때문에. – Henry

+0

다음은 SELECT IN의 성능을 향상시킬 수있는 몇 가지 방법입니다. http://florianreischl.blogspot.ca/2012/03/performance-comparison-of-sql-server.html – Henry

답변

8

귀하의 문제는 VARCHAR 대 NVARCHAR와 관련이있을 수 있습니다.이 두 링크는 ​​어떤 일이있을 수도 것은 cfqueryparam 유니 코드 등의 여부를 VARCHAR에 보내는 경우의 ColdFusion 관리자의 설정이 Querying MS SQL Server G/UUIDs from ColdFusionnvarchar vs. varchar in SQL Server, BEWARE

입니다 도움이 될 수 있습니다. 해당 설정이 열 설정과 일치하지 않으면 (해당 설정을 사용하는 경우) MS SQL은 해당 인덱스를 사용하지 않습니다.

+0

이 설정을 어디에 바꿔야하는지 또는 그것이 사실인지 확인하십니까? 이 특정 데이터 소스에는 '- 라틴 문자 이외의 문자로 구성된 데이터 소스에 대해 하이 ASCII 문자 및 유니 코드 사용 가능'이 선택되어 있지 않습니다. 해야합니까? 열은 varchar입니다. – Nucleon

+0

체크하지 않아야하는 것 같습니다. 차이가 있는지 확인하기 위해 설정을 변경해 볼 수 있습니까? – Yisroel

+0

붐! That is Yisroel, 정말 고마워. 내 로컬 dev에 상자에 나는 그것을 확인하지 않았다. dev/live 서버에서 확인되었습니다. 선택을 취소하자마자 성능이 즉시 향상되었습니다. 나중에이 동일한 문제가 발생했지만 확인해야합니다 (유니 코드가 필요했기 때문에), 인덱스가 유니 코드에있는 것처럼이 방법으로 열을 nvarchar로 지정해야합니까? – Nucleon

0

Mark는 캐시에 잘못된 실행 계획이있는 것으로 나타났습니다. cfqueryparam의 장점 중 하나는 다른 값을 전달할 때 해당 명령문에 대해 캐시 된 계획을 다시 사용할 수 있다는 것입니다. 이것이 작은 목록으로 시도 할 때 아무런 개선이없는 이유입니다. cfqueryparam을 사용하지 않을 때마다 SQL Server는 매번 실행 계획을 수립해야합니다. 캐쉬에 하위 최적 계획이 없으면 일반적으로 나쁜 것입니다. 여기서 설명하는대로 캐시를 지우는 것이 좋습니다. http://www.devx.com/tips/Tip/14401 다음 번에 cfqueryparam을 사용하여 명령문을 실행하면 더 나은 계획을 캐시 할 수 있습니다.

의미가 있습니까?

+1

100 % 확신 할 수는 있지만 의심 할 여지가 있습니다. 다른 크기의 목록에 대한 다른 계획이 될 수 있습니다. CF는 SQL을'SELECT * FROM table WHERE col IN (: listParam)'(즉, 하나의 바인드 매개 변수)로 전달하지 않고 SELECT * FROM table WHERE col IN (: each, : element, : 별도로)'. 따라서 서버는 세 요소 목록에 대한 쿼리를 열 요소 목록과 다른 것으로 보게되며 각 요소가 개별적으로 컴파일 될 것이라는 것을 강하게 의심합니다. –

+1

IN 문이 하나의 목록으로 묶여 있지 않다는 것에 전적으로 동의합니다. 그러나 새로운 준비된 구문으로 식별하고 새로운 쿼리 계획을 계산하게하는 것은 아닙니다. 생각해 보면 IN 문에있는 항목의 수는 테이블 스캔이나 인덱스 등을 사용하지 않아야합니다. – baynezy

+0

관련성이 있지만 동일한 쿼리가 5 가지 다른 방식으로 실행되는지는 확실하지 않습니다. CF9 상자. 각각은 Coldfusion 쿼리 캐싱의 모든 형태를 배제한 것과 동일한 동작을 보여줍니다. 모든 상자가 동일한 DB에 연결되므로 캐싱이 SQL 수준 일 가능성이 있습니다. – Nucleon

0

저는 cfqueryparam이 문제를 일으킬 것이라고 생각하지 않습니다. 실행에 큰 인상을 남겼으므로 cfqueryparam을 사용하려고 할 때 쿼리에 사용하지 않을 인덱스 일 수 있습니다. 개발 컴퓨터에서 동일한 시나리오를 만들었지 만 cfqueryparam을 포함하거나 포함하지 않은 동일한 실행 시간을가집니다. 첫 번째 쿼리에서 테스트로 직접 전달하는 것처럼 오버 헤드가있을 수 있으며 두 번째 Coldfusion에서는 제공된 목록에서 쿼리 매개 변수를 만들어야하지만 다시는 그렇지 않습니다. 나는 "SQL Server Profiler"를 시작하고 서버에서 실행되는 쿼리를 모니터 할 것을 제안합니다. 그러면 500 밀리 초의 비용이 더 많이들 것입니다.