where子句中的大量参数

时间:2012-09-05 07:35:40

标签: sql sql-server

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

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

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

如果{要添加的所选ProductId列表}有多个元素(即10.000),则sql语句执行时间过长,甚至超时。

我对此感到困惑,并且不知道如何解决这个问题。 任何帮助将不胜感激

5 个答案:

答案 0 :(得分: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+,则可以使用table valued parameter。那么查询显然会是这样的。

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

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

然而,通过像这样的大规模排除过滤器的想法似乎是错误的,我无法相信用户是手动逐个排除这些产品。即使是这种情况,我认为,包含过滤器会导致使用内部联接更简单的查询。

答案 1 :(得分:1)

如果我理解正确,主要问题似乎是您没有在数据库中的任何位置存储所选产品的列表。如果你是,你可以执行这样的查询。

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

现在,这不会像许多查询一样好,因为你将从产品中返回数万行。 (您将返回尚未选择的所有产品ID号。)但它在此处以合理的速度执行(在customer_selected_products中为21行,10,000行。)

答案 2 :(得分: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

答案 3 :(得分: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

这应该是最快速,最干净的方式。

答案 4 :(得分:0)

感谢您的意见和建议。

我目前的解决方案是从db获取所有产品(如果需要,过滤)并直接在c#代码中排除选定的产品(不在sql语句中)。

我做了一些测试,它在我的场景中工作得很好。 即我可以在2秒内及时向第二个网格添加100.000个产品。 我也考虑缓存sql结果。它可以提供更好的性能。

如果你知道这个解决方案的任何缺点,请现在就让我。