2

我有一些用 c#、mvc 和 mssql 编写的 Web 应用程序。
有一些表格可供用户选择某些产品。
表格中有两个网格。一个网格显示用户可以选择用于未来处理的产品。其他网格显示已选择的产品。这个工作是这样的:
1. 用户通过复选框从第一个网格中选择产品
2. 然后他单击按钮“添加”
3. 在此之后,网格被刷新。第二个网格显示添加的产品,第一个网格显示没有来自第二个网格的产品的所有产品。

目前数据库中有大约 50.000 种产品。当用户选择要添加的产品过多时,问题在于网格刷新。第一个网格的 Sql 看起来像:

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

如果 { list of selected ProductId to add } 有很多元素(即 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
            )

如果您的问题是关于性能调优的,那么我需要更多关于您的 Schema、数据库的代表性实例以及一些时间来调整和测试一些想法的信息。

但是,像这样通过大量排除过滤器的想法似乎很错误,我无法相信用户正在手动将这些产品逐一排除。即使是这种情况,我认为,包含过滤器会导致使用对集合的内部连接进行更简单的查询。

于 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 号。)但它在这里以合理的速度执行(21 毫秒,在 customer_selected_products 中有 10,000 行。)

于 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'

请注意,为了获得更好的性能,明智的做法是将这些标准存储在第二个表中。现在您可以构建一个查询,例如:

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 个产品添加到第二个网格。我还考虑缓存 sql 结果。它可以提供更好的性能。

如果您知道此解决方案的任何缺点,请现在告诉我。

于 2012-09-05T17:59:54.370 回答