2011-12-20 3 views
1

저는 intersytems 캐시를 처음 사용하고 있으며 캐시에 저장된 데이터를 쿼리 할 때 문제가 발생합니다. 데이터를 정확하게 나타내지 않는 클래스에 의해 노출됩니다. 기본 시스템. 전역 변수에 저장된 데이터는 거의 항상 객체 코드에 정의 된 것보다 큽니다.Intersystems 캐시 - 데이터가 객체 정의를 준수하는지 확인하기위한 객체 코드 유지

마찬가지로 나는 아래와 같은 오류가 자주 발생합니다.

Msg 7347, Level 16, State 1, Line 2 
OLE DB provider 'MSDASQL' for linked server 'cache' returned data that does not match expected data length for column '[cache]..[namespace].[tablename].columname'. The (maximum) expected data length is 5, while the returned data length is 6. 

사람이 객체 정의 (SQL 매핑)들이 전역에서 지속되고있는 데이터를 수용 할 수 있도록 멀리 유지되는 것을 보장하기 위해 품질 프로세스의 몇 가지 유형을 구현하는 경험이 있습니까? 시스템 (5)의 최대 LEN 정의 열을 갖는 특정 예에서

Property columname As %String(MAXLEN = 5, TRUNCATE = 1) [ Required, SqlColumnNumber = 2, SqlFieldName = columname ]; 

그러나 시스템에 저장된 데이터는 6 자이다.

어떻게 이러한 상황을 사전에 모니터링하고 복구 할 수 있습니까?

/*

내가 캐시

*/

+0

@ psr - 복구를 명확히하기 위해 : 나는 sql 테이블 정의보다 더 큰 데이터를 식별하고 sql 테이블을 다시 정의하는 것을 의미합니다. 또는 최소한 데이터 유형이 예상되는 데이터 유형 (유형 및 길이)에 속하는지에 대한 시스템 관리자에게 메트릭을 제공하십시오. –

+0

답변이 마음에 들면 허용으로 표시 할 수 있습니다. – psr

답변

3

그것은 "모니터와 수리"당신을 위해 의미하는 것이 무엇 완전히 명확하지 않다,하지만를 작성하는 것입니다 :

얼마나 제어 당신이 할 데이터베이스 측면에서? 캐시는 데이터 유형 클래스의 LogicalToODBC 메소드를 사용하여 전역에서 ODBC로 변환 할 때 데이터 유형에 대한 코드를 실행합니다. 속성 유형을 % String에서 자신의 클래스 인 AppropriatelyNamedString으로 변경하면 해당 메소드를 재정의하여 자동으로자를 수 있습니다. 그게 니가하고 싶은 일이라면. % Library.CompiledClass 클래스를 사용하여 프로그래밍 방식으로 모든 % String 속성 유형을 변경할 수 있습니다.

캐시 내에서 코드를 실행하여 (이론적으로) 최대 길이보다 큰 속성을 가진 레코드를 찾을 수도 있습니다. 이것은 분명히 전체 테이블 스캔을 필요로합니다. 이 코드를 저장 프로 시저로 노출하는 것도 가능합니다.

다시 한 번 정확하게하려는 것은 무엇인지 모르겠지만 몇 가지 옵션이 있습니다. 아마 당신이 선호하는 것보다 캐시 쪽을 더 깊이 생각해야 할 것입니다.

처음부터 불량 데이터를 방지하는 한 일반적인 대답은 없습니다. 캐시를 사용하면 프로그래머는 개체 또는 테이블 정의를 무시하고 전역에 직접 쓸 수 있습니다. 그런 일이 발생하면 코드를 직접 수정해야합니다.

편집 : 다음은 잘못된 데이터를 검색하는 데 사용할 수있는 코드입니다. 시타 인 재미있는 일을하는 경우에는 효과가 없을 수도 있지만 저에게는 효과적입니다. 메소드 나 태그로 분해하고 싶지 않기 때문에 다소 추한 것입니다. 이는 명령 프롬프트에서 실행하기위한 것이므로 사용자의 목적에 맞게 수정해야합니다.내가 예를 들어, 모든 통합 서비스 패키지에 사용

{ 
    S ClassQuery=##CLASS(%ResultSet).%New("%Dictionary.ClassDefinition:SubclassOf") 
    I 'ClassQuery.Execute("%Library.Persistent") b q 
    While ClassQuery.Next(.sc) { 
    If $$$ISERR(sc) b Quit 
     S ClassName=ClassQuery.Data("Name") 
     I $E(ClassName)="%" continue 
     S OneClassQuery=##CLASS(%ResultSet).%New(ClassName_":Extent") 
     I '$IsObject(OneClassQuery) continue //may not exist 
     try { 
     I 'OneClassQuery.Execute() D OneClassQuery.Close() continue 
     } 
     catch 
     { 

      D OneClassQuery.Close() 
      continue 
     } 
     S PropertyQuery=##CLASS(%ResultSet).%New("%Dictionary.PropertyDefinition:Summary") 
     K Properties 
     s sc=PropertyQuery.Execute(ClassName) I 'sc D PropertyQuery.Close() continue 
     While PropertyQuery.Next() 
     { 
      s PropertyName=$G(PropertyQuery.Data("Name")) 
      S PropertyDefinition="" 
      S PropertyDefinition=##CLASS(%Dictionary.PropertyDefinition).%OpenId(ClassName_"||"_PropertyName) 
      I '$IsObject(PropertyDefinition) continue 
      I PropertyDefinition.Private continue 
      I PropertyDefinition.SqlFieldName=""  
      { 
       S Properties(PropertyName)=PropertyName 
      } 
      else 
      { 
       I PropertyName'="" S Properties(PropertyDefinition.SqlFieldName)=PropertyName 
      } 
     } 
     D PropertyQuery.Close() 

     I '$D(Properties) continue 

     While OneClassQuery.Next(.sc2) { 
      B:'sc2 
      S ID=OneClassQuery.Data("ID") 
      Set OneRowQuery=##class(%ResultSet).%New("%DynamicQuery:SQL") 
      S sc=OneRowQuery.Prepare("Select * FROM "_ClassName_" WHERE ID=?") continue:'sc 
      S sc=OneRowQuery.Execute(ID) continue:'sc 
      I 'OneRowQuery.Next() D OneRowQuery.Close() continue 
      S PropertyName="" 
      F S PropertyName=$O(Properties(PropertyName)) Q:PropertyName="" d 
      . S PropertyValue=$G(OneRowQuery.Data(PropertyName)) 
      . I PropertyValue'="" D 
      .. S PropertyIsValid=$ZOBJClassMETHOD(ClassName,Properties(PropertyName)_"IsValid",PropertyValue) 
      .. I 'PropertyIsValid W !,ClassName,":",ID,":",PropertyName," has invalid value of "_PropertyValue 
      .. //I PropertyIsValid W !,ClassName,":",ID,":",PropertyName," has VALID value of "_PropertyValue 
      D OneRowQuery.Close() 
     } 
     D OneClassQuery.Close() 
    } 
    D ClassQuery.Close() 
} 
0

가장 간단한 해결 방법은 6 이상에 MAXLEN 매개 변수를 증가시키는 이러한 객체 정의를 작성하지 않았다. 저장시 Caché는 MAXLEN 및 TRUNCATE 만 실행합니다. 다른 Caché 코드에서는 일반적으로 괜찮습니다.하지만 불행하게도 ODBC 클라이언트는 이것이 더 엄격하게 집행 될 것으로 기대합니다. 다른 옵션은 SELECT LEFT (럼 이름, 5)처럼 SQL ...

0

가장 간단한 해결책은 올바른 길이로 모든 NVARCHAR 또는 문자 데이터 캐스트 쿼리를 작성하는 것입니다. 이런 식으로 내 데이터가 잘리지 않습니다. 선택 사항 : cachenamespace.tablename.mycolumnName에서

새 쿼리를 최대 (데이터 길이 (mycolumnName를)) SELECT : 먼저 같은 쿼리를 실행 mycolumnname로, 변환 (VARCHAR SELECT 캐스트 (VARCHAR (6)와 같은 mycolumnname을() 8000), memo_field) AS memo_field cachenamespace.tablename.mycolumnName

데이터 가져 오기의 고통은 줄어들지 만 제거되지는 않습니다. 모든 유형의 oledb 공급자를 사용하거나 SQL Server에서 OPENQUERY를 사용하는 경우 내부 OPENQUERY에서 데이터를 검색하는 외부 쿼리가 아니라 Intersystems CACHE db로 전송 된 쿼리에서 캐스트가 발생해야합니다.

+0

합리적이지만 무차별 한 해결책. 나는 새로운 지위로 이전 했으므로이 문제를 더 이상 다루지 않고 시간과 도움에 감사드립니다. 다른 모든 것들과 마찬가지로 찬반 양론을 택할 곳과 찬성하는 곳을 선택하십시오. 모든 것을 varchar (8000)로 정의 할 때처럼 메모리 할당 및 ETL 성능면에서 많은 효율성을 잃을 것입니다. 그러나이 상황에서 나는 선택이 ... 효율적이고 실패하거나, 완전히 비효율적 일지는 모르겠지만 그 일을 끝내는 것이 좋다고 생각한다. 후자는 훨씬 더 가치가 있습니다. –

관련 문제