2

C#、mvc、および mssql で記述された Web アプリケーションがあります。
ユーザーがいくつかの製品を選択できるフォームがあります。
フォームには 2 つのグリッドがあります。1 つのグリッドには、ユーザーが将来の処理のために選択できる製品が表示されます。他のグリッドには、すでに選択されている製品が表示されます。これは次のように機能します
。 1. ユーザーがチェックボックスで最初のグリッドから製品を選択します
。 2. 次に、[追加] ボタンをクリックします
。 3. この後、グリッドが更新されます。2 番目のグリッドには追加された製品が表示され、最初のグリッドには 2 番目のグリッドからの製品がないすべての製品が表示されます。

現在、データベースには約 50.000 の製品があります。問題は、ユーザーが追加する製品を選択しすぎると、グリッドが更新されることです。フリスト グリッドの Sql は次のようになります。

SELECT ProductId, Name, Description, {other columns} 
FROM Products 
WHERE ProductId NOT IN ({ list of selected ProductId to add })

{追加する選択された ProductId のリスト} に多くの要素 (つまり、10.000) がある場合、SQL ステートメントの実行時間が長すぎるか、タイムアウトになることさえあります。

私はこれに行き詰まり、その問題を解決する方法がわかりません。どんな助けでも大歓迎です

4

5 に答える 5

1

製品フィルターを別のテーブルに保存できます。このテーブルは一時的なものにすることも、選択を覚えておきたい場合は永続的なテーブルでインデックスを作成することもできます。

したがって、あなたのステートメントは次のようになります

SELECT
              ProductId
            , Name
            , Description
            ...
    FROM 
            Products 
    WHERE
            ProductId NOT IN 
            (
               SELECT Id FROM #ProductFilter
            )

また、

SELECT
              ProductId
            , Name
            , Description
            ...
    FROM 
            Products 
    WHERE
            ProductId NOT IN 
            (
               SELECT 
                             ProductId 
                   FROM 
                           ProductFilter
                   WHERE
                           FilterId = @filterId
            )

一時テーブルの作成方法、またはフィルターの挿入ProductFilter方法は、フィルターがクエリに渡される方法によって異なります。


SQL Server 2008 以降を使用している場合は、テーブル値パラメーターを使用できます。次に、クエリは明らかに次のようになります。

SELECT
              ProductId
            , Name
            , Description
            ...
    FROM 
            Products 
    WHERE
            ProductId NOT IN 
            (
               SELECT Id FROM @ProductFilter
            )

質問がパフォーマンス チューニングに関するものである場合は、データベースの代表的なインスタンスであるスキーマに関する詳細情報と、いくつかのアイデアを微調整してテストするための時間が必要です。

しかし、このように大規模な除外フィルターを渡すという考えはかなり間違っているように思えます。ユーザーがこれらの製品を 1 つずつ手動で除外しているとは信じられません。その場合でも、包含フィルターを使用すると、セットへの内部結合を使用してクエリが簡単になると思います。

于 2012-09-05T08:03:59.270 に答える
1

私の理解が正しければ、主な問題は、選択した製品のリストをデータベースのどこにも保存していないことにあるようです。もしそうなら、次のようなクエリを実行できます。

select product_id
from products
where product_id not in (select product_id from customer_selected_products);

製品から数万行を返すことになるため、これは多くのクエリほどうまく機能しません。(まだ選択されていないすべての製品 ID 番号を返しています。) しかし、ここでは妥当な速度で実行されます (customer_selected_products の 10,000 行で 21 ミリ秒)。

于 2012-09-05T08:08:05.697 に答える
0

あなたは、ユーザーが名前またはその名前の一部で製品を除外できると述べています。あなたのアンカーがあります。ユーザーが 10,000 個の異なる製品名を除外する可能性は低いですが、特定の属性 (名前のブランドなど) を共有する 10,000 個の製品を除外する可能性が高くなります。

製品 ID を何度も送信するのではなく、より一般的な基準を使用できます。これにより、次のようなクエリが生成されます。

select * 
from products
where p.name NOT LIKE 'brand1%'
and p.name NOT LIKE 'specific product'

パフォーマンスをさらに向上させるには、これらの基準を 2 番目のテーブルに格納することをお勧めします。これで、次のようなクエリを作成できます。

select p.*
from products p
join criteria c
on p.name NOT LIKE c.name
于 2012-09-05T08:19:48.570 に答える
0

TVP (テーブル値パラメーター) をサーバーに送り返すことをお勧めします。その後、クエリは次のように実行できます。

SELECT p.ProductId, Name, Description, {other columns} 
FROM Products p
left join @ExceptedProducts ep on p.ProductId=ep.ProductId
WHERE where ep.ProductId is null

これは、最も速くてクリーンな方法です。

于 2012-09-05T08:24:09.273 に答える
0

アイデアや提案をありがとう。

私の現在の解決策は、db からすべての製品を取得し (必要に応じてフィルタリング)、選択した製品を C# コードで (SQL ステートメントではなく) 直接除外することです。

私はいくつかのテストを行いましたが、私のシナリオではかなりうまく機能しています。つまり、2 秒未満で 100.000 個の製品を 2 番目のグリッドに追加できます。また、SQL結果のキャッシュについても考えています。さらに優れたパフォーマンスを発揮する可能性があります。

このソリューションの欠点を知っている場合は、今すぐ教えてください。

于 2012-09-05T17:59:54.370 に答える