Sql 使用Where子句中可能的许多离散值进行选择

Sql 使用Where子句中可能的许多离散值进行选择,sql,sql-server,Sql,Sql Server,给我一张像这样的桌子 CREATE TABLE [dbo].[Article]( [Id] [int] NOT NULL, [CategoryId] [int] NOT NULL, [Text] [nchar](10) NOT NULL) 允许用户选择一个或多个要查看其数据的类别。通常,他们会选择1-20个类别。为了适应这种情况,我生成了如下参数化查询: SELECT * FROM Article WHERE CategoryId IN (@c1, @c2, @c3,

给我一张像这样的桌子

CREATE TABLE [dbo].[Article](
    [Id] [int] NOT NULL,
    [CategoryId] [int] NOT NULL,
    [Text] [nchar](10) NOT NULL)
允许用户选择一个或多个要查看其数据的类别。通常,他们会选择1-20个类别。为了适应这种情况,我生成了如下参数化查询:

SELECT * FROM Article
WHERE CategoryId IN (@c1, @c2, @c3, @c4, @c5)
然而,在一些罕见的用例中,用户可以合法地选择数百个类别。这让我发现了Linq对实体的局限性,我通过构建来解决这个问题。不幸的是,这只能解决这个问题,因为可以传递给SQL Server的查询的大小有限制

我想重构这个查询以避免任何硬限制。我的第一个想法是创建一个包含所请求的类别的临时表,并对该临时表执行内部联接,以代替in。。。条款但是,我知道临时表可能会非常慢


这个问题有没有更优雅和/或性能更好的解决方案?

您的直觉是正确的,尽管您可能会发现一个表值变量足以代替临时表。在这种情况下,不要担心性能;这并不重要。如果需要,可以在临时表上创建索引,但这似乎不太可能。CategoryId字段上是否有索引?

编辑:

哎呀。我错过了Linq部分

出于性能原因,而不是字符串长度原因,下面是一个值得尝试的替代语法

Select * from dbo.Article art where exists ( select null from ( select 0 as MyV union all select 2 as MyV union all select 3 as MyV ) as derived1 where derived1.MyV = art.CategoryId )

我就是这样处理的

有时,我的变量表被更改为临时表。我测试了两种不同的场景的性能

您可以通过xml传递尽可能多或尽可能少的值

DECLARE @input XML = '<root>
  <category myvalue="1" />
  <category myvalue="2" />
  <category myvalue="3" />
</root>'



declare @holder table ( CatID int )
Insert into @holder (CatID)
SELECT
    myvalue = MyXmlTable.value('(@myvalue)', 'int')
FROM
    @input.nodes('/root/category') AS Tbl(MyXmlTable)


select * from @holder    

SELECT * FROM Article art
where exists (select null from @holder hold where hold.CatID = art.CategoryId
在这里写下:


如果临时表的速度很慢,则它们可能位于错误的物理驱动器上。它们应该在更快的驱动器上,因为它们在使其他查询高效运行方面非常有用,但也许您的Sysdmin没有想到这一点。我指的是类似的文章,而不是我环境中的任何特定性能度量。这篇文章中的许多评论员引用了支持我的建议的个人经验。20多年来,我一直专注于SQL Server数据库的编程和调优。不要被我现在的低声誉所愚弄——我几个小时前才7岁。如果你正在创建一个临时表,我会如下处理:select*从文章中,categoryId在SelectCategoryId中,从诱惑中,存在一些宗教战争。我默认为Where Exists……但您可以测试每个场景。有时会有一些无关紧要的想法……但我发现最好还是测试一下。@granadaCoder:在我的例子中,WHERE EXISTS的速度要快得多,尽管有博客文章声称优化器会解决这个问题。然而,这并不是问题的关键。这里真正的问题是有效地处理N个参数,其中N可能很大。这是我的经验,存在的地方更快。但有一次,我的一位经理告诉我,这并不重要,因为他是在博客上读的,有时在某个地方读过。我想我的最后一个建议可能是……在事情变得有意义之前,你应该一直做下去……因此,也许你不必在这里使用Linq,而应该回到ADO.NET来满足这个特定的需求。“也许有人会想出别的主意。”格拉纳达科德我曾经在可爱的德国城市伍尔茨堡与我的团队一起花了一个月的时间做一个特别的项目,因为我的经理和一个有好主意的人一起打了一轮高尔夫球:-有趣的项目,但是球座话题和你的经理读的博客一样权威。你的建议是合理的。。。当你发现一个性能问题时,请对备选方案进行基准测试。在本例中,我使用的是ADO.Net而不是Linq,尽管我引用的Linq问题是用于同一应用程序中的相关查询。您能帮助我理解Linq选项的select null部分吗?我假设,如果选择了许多参数值,这个Linq表单最终将被转换为一个SQL命令,该命令的最大命令长度相同?因为您需要一些东西,“null”就在那里。你可以放select 1或select hold.CatId或其他任何东西……更重要的是WHERE EXISTS而不是IN子句。是的,你仍然会有最大长度的问题…所以。。。我不知道。我试图提供一个不同的选择和思考。我认为你处在一个艰难的境地。传递一组值,以便可以将它们插入临时表中,以便以后加入…可以工作,但看起来开销很大。所以说到底,我的想法可能有点离谱。但这就是我处理0:N问题的方式