2011-12-20 4 views
1

私はintersytemsキャッシュの使用に慣れており、キャッシュに格納されたデータを照会しているところで、基礎となるシステム。グローバルに格納されるデータは、ほとんど常にオブジェクトコードで定義されているデータよりも大きくなります。Intersystems Cache - データがオブジェクト定義に準拠していることを保証するためのオブジェクトコードの維持

このように、以下のようなエラーが頻繁に発生します。

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マッピング)は、彼らがグローバルで永続化されているデータを収容できるように離れて維持されることを保証するために、品質プロセスのいくつかの種類を実装すると任意の経験を持っていますか?

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

この特定の例では、システムには最大lenの列が定義されていますが、システムに格納されるデータの長さは6文字です。

このような状況を事前に監視して修復するにはどうすればよいですか。

/*

私はキャッシュ

*/

+0

@psr - 修復を明確にするために:私は、sqlテーブル定義より大きいデータを特定し、sqlテーブルを再定義することを意味します。または、最低限、予想されるデータタイプ(タイプと長さ)に含まれるデータの割合についてシステム管理者にメトリクスを提供し始めてください。 –

+0

回答が好きなら、それを承認済みとしてマークできます。 – psr

答えて

3

をあなたのSQLを記述することであるそれはあなたのために意味だろうか「監視および修理」完全に明確ではないですが、:

あなたはどのくらいの制御持っていますデータベース側では? Cacheは、データ型クラスの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(ColumnNameに、5)のように

0

私はすべてのIntegration Servicesパッケージに使用する最も簡単な解決策は、例えば適切な長さに、すべてのデータ型はnvarcharまたはcharデータをキャストするクエリを作成することです。このように、私のデータは切り捨てに失敗しません。 オプション: ファーストのようなクエリを実行します。新しいクエリcachenamespace.tablename.mycolumnName

からマックス(DATALENGTH(mycolumnNameを))SELECT:mycolumnnameとしてSELECT CAST(varchar型としてmycolumnname(6))、 変換(varchar型を( 8000)、memo_field)AS memo_field cachenamespace.tablename.mycolumnNameから

あなたの苦痛は軽減されますが、排除されません。 任意のタイプのoledbプロバイダを使用する場合、またはSQL ServerでOPENQUERYを使用する場合は、 は、内部OPENQUERYからデータを取得する外部クエリではなく、Intersystems CACHE dbに送信されるクエリでキャストが発生する必要があります。

+0

妥当だがブルートフォースの解決策。私は新しい立場に移りました。だからこの問題は扱わなくなりました。あなたの時間と援助に感謝します。ちょうど他のすべてと同じように、どこで賛否両論を取るべきか、そしてどこで賛否両論を取るかの選択。すべてをvarchar(8000)として定義するとき、メモリ割り当てやETLパフォーマンスの面で多くの効率を失うことになります。しかし、このような状況では、選択肢が効率的で失敗しているか、完全に非効率的ではあるが、仕事を終わらせるように、私はその大丈夫と思う。後者ははるかに価値があります。 –

関連する問題