2012-03-18 5 views
6

Nhibernate perfilador muestra un montón de mensajes de error sobre el plan de consulta:Diferentes tamaños de parámetros resultan en caché plan de consulta ineficaz

Diferentes tamaños de parámetros resultan en uso de la caché plan de consulta ineficaz

También le lleva a una explicación en http://nhprof.com/Learn/Alerts/UncachedQueryPlan y le advierte sobre el uso del parámetro prepare_sql = true al construir la sesión. Lo hago de esa manera con fluidez:

.ExposeConfiguration(configuration => configuration 
    .SetProperty("current_session_context_class", "thread_static") 
    .SetProperty("prepare_sql", "true") 
    .SetProperty("generate_statistics", "true") 
    ) 

Pero parece que no está funcionando, ya que los mensajes de error todavía están allí. ¿Es eso una limitación en OracleClientConfiguration o lo estoy haciendo mal?

Editar Para proporcionar alguna información más sobre esto ...

En mi repositorio hago esto

session.Query<TEntity>.Where(predicate).ToList(); 

y esta es la llamada

var value = ParameterRepository.First(p => (p.Pipeline.Id == pipelineId && p.Name == name)); 

Por ejemplo, las son dos SQL generados a partir de esta llamada y ese perfil de nhibernate muestra como "Diferentes tamaños de parámetros resultan en un plan de consulta ineficiente caché nosotros edad"

select GUID1_12_, 
     PARAMETER2_12_, 
     PARAMETER3_12_, 
     GUID4_12_ 
from (select pipelineex0_.GUID_PIPELINE_EXEC_PARAMETER as GUID1_12_, 
       pipelineex0_.PARAMETER_NAME    as PARAMETER2_12_, 
       pipelineex0_.PARAMETER_VALUE    as PARAMETER3_12_, 
       pipelineex0_.GUID_PIPELINE_TRACKING  as GUID4_12_ 
     from FCT_PIPELINE_EXEC_PARAMETER pipelineex0_ 
     where pipelineex0_.GUID_PIPELINE_TRACKING = 'A5916E73CF1E406DA26F65C24BFBF694' /* :p0 */ 
       and pipelineex0_.PARAMETER_NAME = 'lid' /* :p1 */) 
where rownum <= 1 /* :p2 */ 

y segundo

select GUID1_12_, 
     PARAMETER2_12_, 
     PARAMETER3_12_, 
     GUID4_12_ 
from (select pipelineex0_.GUID_PIPELINE_EXEC_PARAMETER as GUID1_12_, 
       pipelineex0_.PARAMETER_NAME    as PARAMETER2_12_, 
       pipelineex0_.PARAMETER_VALUE    as PARAMETER3_12_, 
       pipelineex0_.GUID_PIPELINE_TRACKING  as GUID4_12_ 
     from FCT_PIPELINE_EXEC_PARAMETER pipelineex0_ 
     where pipelineex0_.GUID_PIPELINE_TRACKING = 'A5916E73CF1E406DA26F65C24BFBF694' /* :p0 */ 
       and pipelineex0_.PARAMETER_NAME = 'period' /* :p1 */) 
where rownum <= 1 /* :p2 */ 

mi humilde opinión, es esta PARAMETER_NAME con 'tapa' y 'período' que está generando diferentes planes de consulta.

gracias de antemano

+0

¿Cuáles son los diferentes planes de ejecución de Oracle? – steve

+0

Ahora no me explico cómo es el plan de consulta de Oracle, pero el escenario es bastante similar en [el señalado en la descripción del problema de ayende] (http://nhprof.com/Learn/Alerts/UncachedQueryPlan). En pocas palabras, dice que nhibernate debe confiured para ejecutar querie en un plan de consulta amigable y, por lo que veo, no funciona. – guillem

+0

bueno, recomendaría un enfoque más analítico, de lo contrario, es de prueba y error. ¿Cuáles son los errores? – steve

Respuesta

0

para generar el mismo plan cada vez que el parámetro debe ser ajustado a la misma longitud independientemente del valor del parámetro.

Puede personalizar la implementación del controlador para establecer la longitud del parámetro de consulta a la longitud del campo especificada en su asignación.

public class CustomOracleClientDriver : OracleClientDriver 
{ 
    protected override void InitializeParameter(IDbDataParameter dbParam, string name, SqlType sqlType) 
    { 
     base.InitializeParameter(dbParam, name, sqlType); 

     if (sqlType.LengthDefined) 
      dbParam.Size = sqlType.Length; 
    } 
} 

(NOTA: Heredar de OracleDataClientDriver si está utilizando ODP.Net)

Si está utilizando Fluido NHibernate registrar su aplicación piloto como este:

Fluently.Configure() 
       .Database(
        OracleDataClientConfiguration.Oracle10 
         .ConnectionString(c => c.FromAppSetting("ConnectionString")) 
         .Driver<CustomOracleClientDriver>()) 
0

He probado esto con un OracleClientDriver reemplazado (usando el viejo controlador Microsoft Oracle, no ODP.NET), similar al código en la respuesta de mattk, y no vi ninguna diferencia en la ejecución de Oracle, aunque los parámetros de cadena ahora tienen un tamaño común.

Here's mi publicación en Stackexchange DBA.

Oracle Enterprise Manager no mostró consultas duplicadas para mi NHibernate generado SQL, y en ambas versiones, cada llamada provocó un análisis (hasta alrededor de 1000 para pruebas largas), pero muy pocos análisis, sin diferencias entre variable y fija longitud del parámetro

De hecho, Oracle creó planes de consulta duplicados solo para consultas sin parámetros de enlace, pero con valores concatenados en la cadena SQL (algo que se debe evitar en SQL codificado). Entonces ahora me parece que el tamaño del parámetro no importa para Oracle, cuando se trata de reutilizar planes de consulta (o, en términos de Oracle, compartir cursor).

Oracle probablemente solo compare la cadena SQL para la coincidencia de planes, mientras que SQL Server también verifica las definiciones de los parámetros. También puede ver una diferencia cuando se mira en el SQL dinámico comandos EXECUTE IMMEDIATE (Oracle) y sp_executesql (SQL Server): sp_executesql también para crear una cadena decon las definiciones de parámetros (en una cadena, no como parámetros para la llamada sp_executesql sí mismo!). Sé que NHibernate/ADO.NET usa sp_executesql al enviar consultas parametrizadas a SQL Server, por lo que es probable que tenga un manejo diferente bajo SQL Server. Además, al conectarse a SQL Server a través de NHibernate, todos los parámetros de cadena tienen tamaños únicos (desde la asignación de NHibernate o la longitud máxima predeterminada), por lo que es probable que el problema se haya solucionado cuando sea relevante. ¡Corrígeme si estoy equivocado!

Usar Prepare/prepare_sql en ADO.NET/NHibernate tiene algunas desventajas: según la implementación, antes de ejecutar cualquier SQL, se debe enviar una solicitud de preparación a la base de datos, la aplicación debe mantener un control para la declaración preparada y puede usarse solo para una conexión. Significado: se deben crear nuevos identificadores con frecuencia. Cuando probé con Oracle y ODP.NET, fue algo más lento que la versión no preparada, aunque consultar por manejador es (poco) más eficiente que el SQL parametrizado, emparejado en la base de datos por cadena de igualdad. Probablemente, Preparar es bueno si la aplicación utiliza muchas veces la misma consulta dentro de la misma conexión de base de datos o sesión de NHibernate.

Cuestiones relacionadas