C# 使用替换和长度检查避免SQL不在
在这种情况下,我必须动态创建我的SQL字符串,并且我尝试在可能的情况下使用paramaters和sp_executesql,以便重用查询计划。在做了大量的在线阅读和个人体验后,我发现“不在”和“内部/左侧连接”在基本(最左侧)表很大(1.5M行,约50列)的情况下执行速度慢且成本高。我也读过,应该避免使用任何类型的函数,因为它会减慢查询速度,所以我想知道哪种更糟糕 我过去曾使用过这种解决方法,但我不确定这是否是最好的方法,以避免在传递包含3个字符串的列表时(例如,在元素之间)对项目列表使用“不在”选项: 而不是:C# 使用替换和长度检查避免SQL不在,c#,.net,sql,sql-server,tsql,C#,.net,Sql,Sql Server,Tsql,在这种情况下,我必须动态创建我的SQL字符串,并且我尝试在可能的情况下使用paramaters和sp_executesql,以便重用查询计划。在做了大量的在线阅读和个人体验后,我发现“不在”和“内部/左侧连接”在基本(最左侧)表很大(1.5M行,约50列)的情况下执行速度慢且成本高。我也读过,应该避免使用任何类型的函数,因为它会减慢查询速度,所以我想知道哪种更糟糕 我过去曾使用过这种解决方法,但我不确定这是否是最好的方法,以避免在传递包含3个字符串的列表时(例如,在元素之间)对项目列表使用“不在
[col] NOT IN('ABD', 'RDF', 'TRM', 'HYP', 'UOE')
…假设字符串列表的长度为1到大约80个可能的值,并且此方法也不适合进行参数化
在本例中,我可以使用“=”表示不在,我将使用传统的列表技术表示在,或!=如果这是一个更快的方法,尽管我对此表示怀疑。这比使用NOT IN快吗
作为可能的第三种选择,如果我知道所有其他可能性(可能性,可能比列表长80-95倍)并通过这些可能性会怎么样;这将在应用程序的业务层中完成,以减轻SQL Server的工作负载。查询计划重用的可能性不是很高,但是如果它能让一个大的讨厌的查询缩短一两秒,为什么不呢
我还擅长SQL CLR函数的创建。既然上面是字符串操作,那么CLR函数会是最好的吗
想法
提前感谢您的帮助/建议等
我发现,当基表(最左侧)很大时,“notin”和“INNER/LEFT JOIN”的执行速度很慢,成本也很高
如果正确地为表编制索引,速度应该不会太慢。如果您有一个依赖子查询,则可能会使查询速度变慢。也就是说,必须为表中的每一行重新计算查询,因为子查询引用外部查询中的值
我还读到,应该避免使用任何类型的函数,因为它会减慢查询速度
视情况而定<代码>从…中选择函数(x)可能不会对性能产生很大影响。问题在于在查询的其他位置使用列的函数时,例如连接条件、WHERE子句或ORDER BY,因为这可能意味着无法使用索引。但是,一个定值函数不是问题
关于您的查询,我会先尝试使用
[col]NOT IN('ABD','RDF','TRM','HYP','UOE')
。如果这很慢,请确保您已对该表进行了适当的索引。首先,由于您只筛选出了一小部分记录,因此可能根本没有使用列上的索引,因此SARG功能是没有意义的
这样就剩下了查询计划重用
- 如果您使用的是SQL Server 2008,请将
@param1
替换为表值参数,并让应用程序传递该参数,而不是分隔列表。这完全解决了你的问题
- 如果您使用的是SQLServer2005,我认为这无关紧要。您可以拆分带分隔符的列表并对表使用
不在
/不存在
,但是如果在列
上得不到索引查找又有什么意义呢
有人能讲到最后一点吗?将列表拆分为一个表变量,然后反连接它是否可以节省足够的CPU周期来抵消设置成本
编辑,SQL Server 2005使用XML的第三种方法,灵感来自OMG Ponies的链接:
DECLARE @not_in_xml XML
SET @not_in_xml = N'<values><value>ABD</value><value>RDF</value></values>'
SELECT * FROM Table1
WHERE @not_in_xml.exist('/values/value[text()=sql:column("col")]') = 0
在xml中声明@not_
设置@not_in_xml=N'ABDRDF'
从表1中选择*
其中@not_在_xml.exist('/values/value[text()=sql:column(“col”)]')=0
我不知道与分隔列表或TVP相比,它的性能有多好。正如Donald Knuth经常(错误)引用的那样,“过早优化是万恶之源”。
因此,首先,您确定如果您以最清晰、最简单的方式(既写又读)编写代码,它的执行速度会很慢吗?如果没有,请在开始使用任何“聪明”的优化技巧之前检查它
如果代码很慢,请仔细检查查询计划。大多数情况下,查询执行比查询编译花费的时间要长得多,因此通常您不必担心查询计划的重用。因此,构建最佳索引和/或表结构通常比调整查询的构建方式提供更好的结果
例如,我严重怀疑使用LEN和REPLACE的查询是否比不使用LEN和REPLACE的查询具有更好的性能—在这两种情况下,所有行都将被扫描并检查是否匹配。对于足够长的列表,MSSQL优化器将自动创建临时表以优化相等比较。
更重要的是,像这样的技巧往往会引入bug:比如说,如果[col]='AB',您的示例将无法正常工作
IN查询通常比NOT IN查询快,因为对于IN查询,只有一部分行足以进行检查。该方法的效率取决于您是否能够足够快地为输入获取正确的列表
说到将可变长度列表传递给服务器,这里有很多关于SO和其他地方的讨论。一般来说,您的选择是:
- 表值参数(仅限MSSQL 2008+版)
- 动态构造的SQL(容易出错和/或不安全)
- 临时表(适用于长列表,短列表的写入和执行时间开销可能太大)
- 分隔字符串(适用于“行为良好”值的短列表,如少数整数)
- XML参数(有点复杂,但工作良好-如果您使用一个好的XML库,并且不“手工”构造复杂的XML文本)
下面是一篇关于这些技术以及其他一些技术的综述。W
DECLARE @not_in_xml XML
SET @not_in_xml = N'<values><value>ABD</value><value>RDF</value></values>'
SELECT * FROM Table1
WHERE @not_in_xml.exist('/values/value[text()=sql:column("col")]') = 0