sp_executesql con N argumentos está causando un rendimiento lento

Estoy teniendo un problema de rendimiento con un objeto Railer activerecord usando activerecord_sqlserver_adapter. Aquí es cómo se ve el sql que se genera y se ejecuta muy lento;

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

Lo siguiente corre muy rápido;

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

El adaptador coloca N delante de cada elemento en la cláusula where que ralentiza las cosas. El plan de ejecución sugiere que agregue un índice, pero eso parece innecesario y esta es una base de datos heredada.

¿Alguien tiene alguna sugerencia de cómo podría acelerar esto?

Recomiendo leer cómo el código de acceso a datos afecta el rendimiento de la base de datos y disminuye la velocidad de la aplicación, ¿rápido en el SSMS? Entendiendo los misterios del rendimiento . Ambos artículos cubren este tema, y ​​mucho más, con gran detalle.

El resumen es que las reglas de Precedencia de Tipo de Datos dictan que una operación que involucre tanto un VARCHAR como un NVARCHAR operandos debe ocurrir al convertir el VARCHAR (rango de precedencia 27) a NVARCHAR (rango de precedencia 25). Por lo tanto, su consulta es realmente como si tuviera un problema de rendimiento con un objeto Railer activerecord usando activerecord_sqlserver_adapter. Aquí es cómo se ve el sql que se genera y se ejecuta muy lento;

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

Esto no es sargable, lo que significa que se ignorará un índice en constituent_id se realizará una exploración de tabla en su lugar.

Pero la verdadera pregunta aquí es ¿por qué usas cuerdas para lo que camina y canta como un int ? ¿No debería la columna constituyente_id ser int , junto con los parámetros pasados?

¿Constituent_id es una cadena o un número? Si es una cadena, ¿no hay forma de indicarle a su adaptador si es varchar o nvarchar? Lo que probablemente te está matando es la conversión implícita resultante.

¿Ha pensado en insertar primero los valores en una tabla y luego realizar una unión? Esto se puede hacer fácilmente pasando una cadena separada por comas y luego usando un UDF o XML para “dividir” la lista en una tabla con el tipo de datos correspondiente. Posiblemente ver la consulta SQL para que coincida con las palabras clave?

La ‘N’ indica una cadena Unicode. Supongo que los tipos en SQL Server no son Unicode (es decir, VARCHAR en lugar de NVARCHAR) y, por lo tanto, este código está generando una conversión implícita. Mire el plan de ejecución y vea si puede ver convert_implicit en los operadores. Si este es el caso, deberá averiguar por qué el generador de código está asumiendo que las variables son Unicode. Puede haber alguna forma de declarar las variables como un tipo diferente que no se traduzca a Unicode.

los recuentos seleccionados realizan un escaneo completo de la tabla, y una cláusula de entrada también es lenta, la consulta realizará un escaneo completo de la tabla debido al recuento selecto.

dividir la consulta en pequeñas consultas de una línea. almacene el conteo o use la partición para obtener un mejor rendimiento.

Los índices, ayudarán.