Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/80.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
其中,在SQL Server中,使用表类型比使用硬编码值的性能要好得多_Sql_Sql Server_Where In_Table Valued Parameters - Fatal编程技术网

其中,在SQL Server中,使用表类型比使用硬编码值的性能要好得多

其中,在SQL Server中,使用表类型比使用硬编码值的性能要好得多,sql,sql-server,where-in,table-valued-parameters,Sql,Sql Server,Where In,Table Valued Parameters,我有两个基本相同的查询,至少如果我没有遗漏什么的话 声明@siloIds SiloIdsTableType 插入@siloIds值 1,2,3 -问题1 挑选* 来自[交易] 哪里 1,2,3中的筒仓 和时间>'2000-02-01' -问题2 挑选* 来自[交易] 哪里 从@SiloId中选择SiloId中的SiloId 和时间>'2000-02-01' 我认为一个查询不能超过查询本身中声明的常量,但显然第一个查询比第二个查询慢几倍。SQL server似乎不够聪明,无法为硬编码值提供一个好的

我有两个基本相同的查询,至少如果我没有遗漏什么的话

声明@siloIds SiloIdsTableType 插入@siloIds值 1,2,3 -问题1 挑选* 来自[交易] 哪里 1,2,3中的筒仓 和时间>'2000-02-01' -问题2 挑选* 来自[交易] 哪里 从@SiloId中选择SiloId中的SiloId 和时间>'2000-02-01' 我认为一个查询不能超过查询本身中声明的常量,但显然第一个查询比第二个查询慢几倍。SQL server似乎不够聪明,无法为硬编码值提供一个好的计划,或者我在这里遗漏了什么

似乎一个人不应该在长列表中使用where-in,而应该始终青睐TVP

另外,我在查询中使用了1000个值,而不是1,2,3

p.p.S.我在SiloId ASC,Time ASC上有一个非聚集索引,但由于某种原因,第一个查询似乎没有使用它来支持聚集索引扫描

p.p.p.S.执行计划分担成本14%至86%,支持第二次查询

执行计划:


当您使用一个表变量或TVP(这是同一件事)时,SQL Server使用一个固定的估计值,即它只会从表中获得1行,下面是基数1。这意味着它假设SiloId连接过滤器是非常有选择性的,它将对其进行优先级排序,并执行嵌套循环连接以仅获取这些行,然后及时进行过滤

而当使用常量时,精确的大小是硬编码的。无论出于何种原因,可能是糟糕的统计数据,它都假定时间更具选择性,因此优先于其他过滤器

当表变量plan中或主表中有很多行时,表变量plan会下降,因为这样会得到很多键查找,这可能会很慢

理想情况下,您希望编译器预先知道表变量的大小。您可以通过多种方式执行此操作,如:

跟踪标志2453,如果基数非常不同,则会导致重新编译如果可以冒TF的风险,这是个好主意 选项重新编译每次都重新编译,这本身可能是低效的 临时表不能作为参数
发布执行计划和IO统计信息。众所周知,在我第一次连续运行查询5次以检查数据时,您可能看到了缓存数据的效果。事实上,情况正好相反。与硬编码值不同,表变量没有统计信息。优化器假定@siloIds`只包含一行。不同版本的SQL Server之间存在差异,但通常情况下,优化器无法知道一个表中的内容,一行可变5次,这意味着第一个查询将支付相应的费用,而所有其他查询仅从RAM中读取。无论查询运行多少次,第一个查询总是显示得慢得多。假设时间由一个索引覆盖,主要延迟来自IOhow它如何使用正确的索引,然后假设有一行,而不使用1000个硬编码值?奇怪的是,当它假设只有一行时,它使用正确的索引,但有1000行时它不使用:正如我解释的,这是因为基数计算。1000个键查找对于一个小表来说是一个相当大的数目。您是否尝试过使用fullscanI更新统计信息[Transaction],我在另一个数据集上尝试过,然后硬编码的where in为适当的计划提供了索引搜索,那么执行时间大致相同。我在第一个数据集中有1百万行,在第二个数据集中有2百万行,所以它们非常简单big@Charlieface表参数的索引仅出现在执行计划中。即使假设表参数中只有一行,使用索引也可以获得更好的执行效果plan@PanagiotisKanavos是的,我知道,在这种情况下,虽然这只是一个快乐的巧合。另一个计划也应该是嵌套循环。我通常在我的表类型上创建索引,因为我知道/确保数据是唯一的。我不希望得到正确的统计数据和临时表参数吗!