带有N个参数的sp_executesql导致性能降低

时间:2012-01-25 00:10:24

标签: ruby-on-rails sql-server

使用activerecord_sqlserver_adapter我遇到了Rails activerecord对象的性能问题。这是生成的sql看起来很像并且运行速度非常慢;

EXEC sp_executesql N'SELECT COUNT(*) FROM [constituents] WHERE [constituents].[constituent_id] IN (N''10016125'', N''483663'', N''530657'', N''535217'')'

以下运行非常快;

EXEC sp_executesql N'SELECT COUNT(*) FROM [constituents] WHERE [constituents].[constituent_id] IN (''10016125'', ''483663'', ''530657'', ''535217'')'

适配器将N放在where子句中的每个项目前面,这会减慢速度。执行计划建议我添加一个索引,但这似乎是不必要的,这是一个遗留数据库。

有没有人建议我如何加快速度?

4 个答案:

答案 0 :(得分:3)

我强烈建议您阅读How Data Access Code Affects Database PerformanceSlow in the Application, Fast in SSMS? Understanding Performance Mysteries。这两篇文章都非常详细地介绍了这个主题。

摘要是Data Type Precedence的规则规定,通过转换VARCHAR(优先级),必须发生涉及VARCHARNVARCHAR操作数的操作的操作等级27)到NVARCHAR(优先等级25)。因此您的查询非常喜欢 我使用activerecord_sqlserver_adapter来处理Rails activerecord对象的性能问题。这是生成的sql看起来很像并且运行速度非常慢;

SELECT COUNT(*) 
FROM [constituents] 
WHERE CAST([constituents].[constituent_id] as NVARCHAR(...))
IN (N''10016125'', N''483663'', N''530657'', N''535217'');

这是不可更改的,这意味着将忽略constituent_id上的索引,而是执行表扫描。

但真正的问题是,为什么你会像int一样使用字符串来行走和嘎嘎叫? construct_id列不应该是int,还有传入的参数吗?

答案 1 :(得分:1)

construct_id是字符串还是数字?如果是字符串,是否无法指示您的适配器是varchar还是nvarchar?可能会杀死你的是隐式转换。

您是否考虑过先将值插入表中然后再执行连接?这可以通过传入逗号分隔的字符串然后使用UDF或XML将列表“拆分”为具有匹配数据类型的表来轻松完成。可能会看到SQL query to match keywords?

答案 2 :(得分:1)

'N'表示Unicode字符串。我猜测SQL Server中的类型不是Unicode(即VARCHAR而不是NVARCHAR),因此此代码生成隐式转换。查看执行计划,看看是否可以在运算符中看到convert_implicit。如果是这种情况,您需要弄清楚代码生成器假设变量是Unicode的原因。可能有某种方法可以将变量声明为不会转换为Unicode的不同类型。

答案 3 :(得分:0)

select count进行全表扫描,in子句也很慢,由于select count,查询将进行全表扫描。

将查询分解为小的一行查询。存储计数或使用分区来获得更好的性能。

索引,会有所帮助。