7

270を超える更新フィールドで大きなテーブルを更新する必要があります。

私は.NETに比較的慣れていないので、この場合に使用するのに適したものをアドバイスする必要があります。SqlCommand、ある種のメモリマップテーブルまたはDataSet、あるいはDBからのメタデータを使用してある種の自動生成オブジェクトが存在するのでしょうか。助けてください。

理由:私は古い大きなDelphi7アプリケーションを持っています。その一部は、大きな構造にマーシャリングされ、最終ステップでDBに格納されるいくつかのパケットをソケットでリッスンする役割を果たします。現在、この部分を新しいC#サービスに移植していますが、少なくとも実際には同じロジックを保持する必要があります。問題は、構造がBIG(220フィールド以上)であり、それが格納されているテーブルには300近くのフィールドがあることです。私の220フィールドの構造から、他の約50フィールドが差し引かれ、計算され、すべてDBで更新する必要があります。実際のDelphiコードは、テーブル自体のように数年にわたって成長した醜いもので、次のようなものです。

'UPDATE TABLE_NAME ' +
  '  MSG_TYPE = ' + IntToStr(integer(RecvSruct.MSG_TYPE)) + ' ' + 
  ' ,SomeFLOATfield = ' + FloatToStr(RecvSruct.SomeFLOATfield) + ' ' + 
  ... //and other over 270 fileds here
'WHERE ID = ' + IntToStr(obj.ID)

動的SQLなどはありません。実際にはDB構造を変更できません。そのため、コードのみで再生する必要があり、コードを適切に変換できるかどうかはわかりません。表は、一部のレポートと統計に使用されます。計算された/差し引かれたフィールドのいくつかは、ソースコードのいくつかの定数を処理する必要があります。

使用された開発ツール:MS SQL Server 2000、C#.net2.0、VS2008

4

5 に答える 5

2

ole dbが機能する方法は文字列を使用するため、ここで最も簡単な解決策が適用されます。したがって、270、500、1000のパラメーターを渡すには、単一の文字列を渡すだけです。270のパラメーターを含む文字列は、おそらく2kbをはるかに下回ります。パフォーマンスが低下します。ここにxmlソリューションがありますが、それはリンゴとオレンジだけです。まだ文字列を渡していますが、xmlを処理するには追加のコードが必要になります。つまり...アーキテクチャは次のようになります。

  1. 270個の入力パラメーターを持つSQLサーバーのストアドプロシージャ:

     Create Procedure sp_Example1 
     (@param1 [type], @param2 [type], @param3 [type], etc...)
     AS 
     BEGIN
     [SQL statements]
     END
    
  2. 270個のパラメーターを持つコマンドオブジェクト:

    SqlCommand cmd = new SqlCommand("sp_Example1", [sqlconnectionstring]);
    cmd.Parameters.Add(New SqlParameter("@param1", param1.value));
    cmd.Parameters.Add(New SqlParameter("@param2", param2.value));
    cmd.Parameters.Add(New SqlParameter("@param3", param3.value));
    

まだかなり集中的な操作を行っていることを忘れないでください。ただし、ベンチマークは古いアプリケーションである必要があります。フレームワークはより多くのコンピューティングオーバーヘッドを必要とするため、少し悪い場合でも心配する必要はありません。

なぜコードがフォーマットされないのかわかりません...

于 2013-02-27T22:56:50.470 に答える
1

Ok。新しいストアドプロシージャを追加できるので、すべての値をパッケージ化して、XMLとしてストアドプロシージャに送信することをお勧めします。

ここにちょっとした例があります:http: //granadacoder.wordpress.com/2009/01/27/bulk-insert-example-using-an-idatareader-to-strong-dataset-to-sql-server-xml/

幸いなことに、私が持っている例は古く、SQL Server 2000(OPENXMLを使用)にコード化されています。

..

これは、300個のパラメーターをストアドプロシージャIMHOに送信するよりも優れています。

もう1つの利点は、複数行のデータがある場合は、それを出荷することもできます。

.....。

その「要点」:

まず、ここで2000の「パブ」データベースを取得できます。

http://www.microsoft.com/en-us/download/details.aspx?id=23654

次に、このストアドプロシージャを追加します。

/ * USP * /

DROP PROCEDURE dbo.uspTitleUpsert
GO





CREATE  PROCEDURE dbo.uspTitleUpsert (
    @xml_doc TEXT , 
    @numberRowsAffected int output  --return
)

AS 

SET NOCOUNT ON 

DECLARE @hdoc INT -- handle to XML doc

DECLARE @errorTracker int -- used to "remember" the @@ERROR

DECLARE @updateRowCount int
DECLARE @insertRowCount int 


--Create an internal representation of the XML document.    
EXEC sp_xml_preparedocument @hdoc OUTPUT, @XML_Doc    



-- build a table (variable table) to store the xml-based result set
DECLARE @titleupdate TABLE (  
    identityid int IDENTITY (1,1) , 

title_id varchar(6) , 
title varchar(80) , 
type varchar(32) , 
pub_id varchar(32) , 
price money , 
advance money , 
royalty varchar(32) , 
ytd_sales varchar(32) , 
notes TEXT , 
pubdate datetime
)




--the next call will take the info IN the @hdoc(with is the holder for @xml_doc), and put it IN a variableTable
INSERT @titleupdate
    (
        title_id ,
        title ,
        type ,
        pub_id ,
        price ,
        advance ,
        royalty ,
        ytd_sales ,
        notes ,
        pubdate
    )
SELECT  
    title_id ,
    title ,
    type ,
    pub_id ,
    price ,
    advance ,
    royalty ,
    ytd_sales ,
    notes ,
    getdate() /*dbo.udf_convert_xml_date_to_datetime (pubdate)*/
FROM  
    -- use the correct XPath .. the second arg ("2" here) distinquishes
    -- between textnode or an attribute, most times with
    --.NET typed datasets, its a "2"
    --This xpath MUST match the syntax of the DataSet
 OPENXML (@hdoc, '/TitlesDS/Titles', 2) WITH (  

    title_id varchar(6) , 
    title varchar(80) , 
    type varchar(32) , 
    pub_id varchar(32) , 
    price money , 
    advance money , 
    royalty varchar(32) , 
    ytd_sales varchar(32) , 
    notes TEXT , 
    pubdate varchar(32)

)  


EXEC sp_xml_removedocument @hdoc



select * from @titleupdate



SET NOCOUNT OFF




Update 
    dbo.titles 
set 
    title = vart.title , 
    type = vart.type , 
    pub_id = vart.pub_id , 
    price = vart.price , 
    advance  = vart.advance , 
    royalty  = vart.royalty , 
    ytd_sales  = vart.ytd_sales , 
    notes  = vart.notes , 
    pubdate  = vart.pubdate 
FROM
    @titleupdate vart , dbo.titles realTable
WHERE
    (rtrim(upper(realTable.title_id))) = ltrim(rtrim(upper(vart.title_id)))
    and
    exists 
    (
        select null from dbo.titles innerRealTable where (rtrim(upper(innerRealTable.title_id))) = ltrim(rtrim(upper(vart.title_id)))
    )


Select @updateRowCount = @@ROWCOUNT

INSERT INTO dbo.titles
    (
        title_id ,
        title ,
        type ,
        pub_id ,
        price ,
        advance ,
        royalty ,
        ytd_sales ,
        notes ,
        pubdate
    )
Select
    title_id ,
    title ,
    type ,
    pub_id ,
    price ,
    advance ,
    royalty ,
    ytd_sales ,
    notes ,
    pubdate
FROM
    @titleupdate tu
WHERE
    not exists 
    (
        select null from dbo.titles innerRealTable where (rtrim(upper(innerRealTable.title_id))) = ltrim(rtrim(upper(tu.title_id)))
    )

Select @insertRowCount = @@ROWCOUNT

print '/@insertRowCount/'
select @insertRowCount
print ''

print '/@updateRowCount/'
select @updateRowCount
print ''


select @numberRowsAffected = @insertRowCount + @updateRowCount



--select * from titles

SET NOCOUNT OFF


GO




--GRANT EXECUTE on dbo.uspTitleUpsert TO pubsuser



GO

/*使用例*/

EXEC dbo.uspTitleUpsert
'
<TitlesDS>
    <Titles>
        <title_id>PN3333</title_id>
        <title>Peanut Cooking</title>
        <type>trad_cook</type>
        <pub_id>0877</pub_id>
        <price>3.33</price>
        <advance>4444.00</advance>
        <royalty>1</royalty>
        <ytd_sales>33</ytd_sales>
        <notes>Peanut Cooking Notes</notes>
        <pubdate></pubdate>
    </Titles>

    <Titles>
        <title_id>SSMS4444</title_id>
        <title>Sql Server Management Studio</title>
        <type>programming</type>
        <pub_id>0877</pub_id>
        <price>13.33</price>
        <advance>5444.00</advance>
        <royalty>2</royalty>
        <ytd_sales>33</ytd_sales>
        <notes>Sql Server Management Studio Notes</notes>
        <pubdate></pubdate>
    </Titles>   

</TitlesDS>
'
, 0
于 2013-02-27T22:31:30.507 に答える
0

Simple.dataを使用すると、コードとロジックを簡素化できます(ただし、.NET 4.0が必要です)。

于 2013-02-27T22:40:52.373 に答える
0
  1. テーブルを新しいテーブルに分割し、結合、切り替え、キャストなどの古いテーブルと同じ名前のビューを作成して、新しいテーブルをレポートの古い構造に変換することができます。

  2. コマンドを使用する場合(投稿したDelphiコードのように)、SQLインジェクションを防ぐためにパラメーターを使用してください。

  3. 現在のDB構造では、マップする列がたくさんあるため、すぐに使用できるORMを使用すると疲れる可能性があります。POCOクラスをタイプセーフモデルとして作成し、データ表記またはカスタム属性を使用してマッピングを簡素化し、属性からその場でSQLコマンドを作成できます。

于 2013-02-27T22:55:42.053 に答える
0

私が恐れているこの帽子のために.net帽子から引き抜く特別なウサギはありません。

一部の完全に独立したフィールドのみが変更され、それらのフィールドのみの更新ステートメントを作成することに関する複雑さを除けば、あなたは詰め込まれています。

これを知っていても、blobは実際には役に立たないため、より適切に保存されているはずです。いずれにせよ真実ではない可能性があります。

パラメータ化されたクエリまたはストアドプロシージャは、コードでは少しきれいに見えますが、とにかくデルファイで実行できたはずです。

ここからそれがどのように行われるべきかを言う方法はありませんが、マイレージを持っているかもしれない1つのアイデアは、現在のテーブルを小さな関数のセット以外のすべてから隠すことです。

たとえば、名前を変更してから、現在の名前でビューを作成する場合です。読んでいるものや(おそらくそれに書き込むかなりのコード)は気付かないでしょう。ビューといくつかのストアドプロシージャを介してのみrawテーブルにアクセスできるようになった場合は、構造をハッキングし始めることができます。

コード(SQLなし)は、アプリケーションとテーブルの間にORMスタイルのアクセスを挿入することだけです。これは、何よりもスキルセットとアプリケーションの組み合わせに基づいて決定する必要があります。

この表である特定の実装からすべてのアプリケーションを切り離すことができ、準備ができていない限り、単に糞便を磨いているだけです。それに貴重なリソースを費やしても意味がありません。

于 2013-02-27T23:02:10.957 に答える