1

最初に、何をする必要があるかを説明し、次にそれをどのように達成できると思うかを説明します。私の現在の計画は理論的には非常に非効率的であるように思われるので、私の質問はそれを達成するためのより良い方法があるかどうかです.

私は 2 つのテーブルを持っています - それらを 'Products' と 'Products_Temp' と呼びましょう。どちらも同じです。サプライヤーからの製品の詳細 (在庫、価格など) を含む多数のファイル (XML または XLS) をダウンロードする必要があります。これらは、Products_Temp テーブルに解析されます。現在、CF スケジュール タスクを使用してダウンロードを処理し、Navicat を使用して実際の解析を行う予定です。これで十分で効率的であることに満足しています。

次のステップは、私が苦労しているところです。ファイルをダウンロードして解析したら、データの変更を探す必要があります。これは Products テーブルと比較されます。変更が見つかった場合は、その行を追加または更新する必要があります (削除する必要がある場合は、単に削除するのではなく、フラグを立てる必要があります)。すべてのデータを比較したら、products_temp テーブルを空にする必要があります。

テーブルを比較してそれに応じて同期する方法は知っていますが、問題は、異なるソースからの複数のファイルを処理するという事実です。製品テーブルと追加/更新のみを使用することを検討しましたが、「フラグ削除」要件をどのように管理できるかわかりません。

現在、私が知っている唯一の方法は、products_temp テーブルをループし、さまざまな cfquery を実行し、完了したら行を削除することです。しかし、それは信じられないほど非効率に思えます。また、何十万もの行を処理する可能性が高いという事実を考えると、すべてを毎日更新しても効果的ではありません。

より良いルートに関する指針やアドバイスをいただければ幸いです。

4

3 に答える 3

2

どちらの応答にも可能性があります。オプションを少し拡張するだけです..

オプション1

mySQLが行ごとに何らかのハッシュをサポートしている 場合、 comodoro の提案のバリエーションを使用してハード削除を回避できます。

変更の識別

変更を識別するには、主キーで内部結合を実行し、ハッシュ値を確認します。それらが異なる場合、製品は変更されており、更新する必要があります。

    UPDATE Products p INNER JOIN Products_Temp tmp ON tmp.ProductID = p.ProductID
    SET    p.ProductName = tmp.ProductName
           , p.Stock = tmp.Stock
           , ...
           , p.DateLastChanged = now()
           , p.IsDiscontinued  = 0
    WHERE  tmp.TheRowHash <> p.TheRowHash

削除された識別

単純な外部結合を使用して、一時テーブルに存在しないレコードを特定し、それらに「削除済み」のフラグを立てます

    UPDATE Products p LEFT JOIN Products_Temp tmp ON tmp.ProductID = p.ProductID
    SET    p.DateLastChanged = now()
           , p.IsDiscontinued = 1
    WHERE  tmp.ProductID IS NULL

新規識別

最後に、同様の外部結合を使用して、「新しい」製品を挿入します。

    INSERT INTO Products ( ProductName, Stock, DateLastChanged, IsDiscontinued, .. )
    SELECT tmp.ProductName, tmp.Stock, now() AS DateLastChanged, 0 AS IsDiscontinued, ...
    FROM   Products_Temp tmp LEFT JOIN Products p ON tmp.ProductID = p.ProductID
    WHERE  p.ProductID IS NULL

オプション #2

行ごとのハッシュが実行できない場合、代替アプローチはシャロンディオの提案のバリエーションです。

一時テーブルに「ステータス」列を追加し、一連の結合を通じて、インポートされたすべてのレコードに「新規」、「変更済み」、または「未変更」のフラグを立てます。(デフォルトは「変更」する必要があります)。

UN-Change の特定

まず、すべてのフィールドで内部結合を使用して、変更されていない製品を識別します。(テーブルに null 許容フィールドが含まれているcoalesce場合は、次のようなものを使用することを忘れnullないでください。

    UPDATE  Products_Temp tmp INNER JOIN Products p ON tmp.ProductID = p.ProductID
    SET     tmp.Status = 'Unchanged'
    WHERE   p.ProductName = tmp.ProductName
    AND     p.Stock = tmp.Stock
    ... 

新規識別

以前と同様に、外部結合を使用して「新しい」レコードを識別します。

    UPDATE  Products_Temp tmp LEFT JOIN Products p ON tmp.ProductID = p.ProductID
    SET     tmp.Status = 'New'
    WHERE   p.ProductID IS NULL

削除のプロセスにより、一時テーブル内の他のすべてのレコードが「変更」されます。ステータスを計算したら、Products テーブルを更新できます。

    /*  update changed products */
    UPDATE Products p INNER JOIN Products_Temp tmp ON tmp.ProductID = p.ProductID
    SET    p.ProductName = tmp.ProductName
           , p.Stock = tmp.Stock
           , ...
           , p.DateLastChanged = now()
           , p.IsDiscontinued = 0
    WHERE  tmp.status = 'Changed'

    /*  insert new products */
    INSERT INTO Products ( ProductName, Stock, DateLastChanged, IsDiscontinued, .. )
    SELECT tmp.ProductName, tmp.Stock, now() AS DateLastChanged, 0 AS IsDiscontinued, ...
    FROM   Products_Temp tmp
    WHERE  tmp.Status = 'New'

    /* flag deleted records */
    UPDATE Products p LEFT JOIN Products_Temp tmp ON tmp.ProductID = p.ProductID
    SET    p.DateLastChanged = now()
           , p.IsDiscontinued = 1
    WHERE  tmp.ProductID IS NULL
于 2012-05-23T08:32:46.127 に答える
2

変更を見つけるために、一致させたいフィールドに基づいて結合を調べます。これは、フィールドの数とそれらがインデックス化されているかどうかによっては遅くなる可能性がありますが、それでもループよりは高速だったと思います。次のようなもの:

SELECT product_id
FROM Products
WHERE product_id NOT IN (
    SELECT T.product_id
    FROM Products_Temp T
    INNER JOIN PRODUCTS P
    ON (
        P.field1 = T.field1
        AND P.field2 = T.field2
        ...
    )
)

不足している製品が一致しないものを見つけるには:

SELECT P.product_id
FROM Products P
LEFT OUTER JOIN Products_Temp T
ON (P.field1 = T.field1
    AND P.field2 = T.field2
    ...)
WHERE T.product_id IS NULL
于 2012-05-22T13:39:38.427 に答える
1

私は一度同様の問題を解決しなければなりませんでした.おそらく解決策はあなたの場合に適用できます(私はColdfusionをあまり知りません). (ソースごとに) そのソースに対応するテーブル Products からすべてを削除し、同じソースの Products_Temp に置き換えてみませんか? ソースごとに一意のフィールドを作成できることを前提としています。SQL コードは次のようになります。

DELETE FROM Products WHERE source_id = x;
INSERT INTO 製品 (field1、field2、...、source_id)
  SELECT フィールド 1、フィールド 2、...、x FROM Products_Temp;

また、ソースがあまり変更されていない場合は、ダウンロード後にハッシュを作成し、変更されていない場合は更新をスキップして、データベースへのアクセスを節約することを検討できます。

于 2012-05-22T08:24:30.327 に答える