2009-02-23 20 views
6

Tengo algunos problemas con linq para las entidades en el marco de la entidad ado.net. Básicamente lo que hago es la siguiente:linq a las entidades generadas sql

var results = (from c in companies 
    where c.Name.StartsWith(letter) 
    select c); 

y esto se traduce a SQL como algo parecido a:

WHERE (CAST(CHARINDEX(@p, [Extent1].[Name]) AS int)) = 1 

que está muy bien, pero mi mesa cuenta con millones de registros por lo que este funciona muy lento. Lo que lo necesito para generar es algo así como:

WHERE Name LIKE @p + '%' 

estoy buscado alta y baja y no puedo encontrar ninguna solución excepto para utilizar un procedimiento almacenado o el uso de Entity SQL ...

¿Hay alguna forma de hacerlo a través de linq? ¿Posiblemente al extender de algún modo el linq al proveedor de linq de entidades, o al interceptar de algún modo el árbol de comandos o la consulta generada?

+0

Es este tipo de cosas que me hace muy relunctant de tirar mi capa de procedimiento almacenado en favor de todo lo que genera SQL. –

Respuesta

2

Guau, ¡esa es una forma realmente extraña de hacerlo! Tenga en cuenta que LINQ-to-SQL (en este caso) usa LIKE @p0 + '%' ... muy extraño.

¿Qué proveedor de EF (base de datos) está utilizando? ¿Servidor SQL?

Como usted dice, un procedimiento almacenado será el trabajo, pero no debería tener de hacer eso ... muy, muy extraño ...

+0

Sí, estoy usando SQL Server 2005. Por lo que he leído, LINQ to SQL proporciona una clase SqlMethods que expone funciones SQL y operadores como LIKE, pero no existe tal cosa en LINQ to Entities. Vaya a la figura ... –

4

No soy un experto en SQL, pero suponiendo que ambos sintaxis:

DONDE (CAST (CHARINDEX (@p, [Extent1] [Nombre]) AS int).) = 1

y

DONDE nombre como @p + '%'

dará como resultado una exploración de tabla o idealmente una exploración de índice. En pocas palabras, realizarán lo mismo. Lo verifiqué al ver los planes de ejecución a continuación. En pocas palabras, debe replantearse el esquema de la base de datos o la forma en que realiza su búsqueda. Este no es un problema LINQ.

Un área posible de mejora: asegúrese de haber indexado la columna que está buscando.

alt text http://download.binaryocean.com/plan1.gif

alt text http://download.binaryocean.com/plan2.gif

+1

Si tiene un índice en la columna Nota/Nombre y la cardinalidad no es demasiado baja, se utilizará en una consulta LIKE 'a%'. No estoy seguro de que el optimizador de consultas pueda usar el índice para una operación CAST (CHARINDEX()). –

+1

Tengo un índice en la columna Nombre de mi base de datos. El LIKE hace un escaneo de índice, el SQL generado (CHARINDEX) realiza un escaneo de tabla, que es por lo que lleva tanto tiempo. –

0

Es "letra" un char? Si hiciste una cadena, ¿qué sucede?

var results = (from c in companies 
    where c.Name.StartsWith(letter.ToString()) 
    select c); 
+0

Es una cadena ... –

0

He intentado utilizar esta sintaxis en lugar

Name.Substring(0, 1) == "E" 

Se genera este SQL

WHERE N'E' = (SUBSTRING([Name], 0 + 1, 1)) 

Tal vez esto es más eficiente?

+0

Sí, lo he intentado también ... Creo que funcionó más o menos igual. –

1

Este es un known issue con Linq para Entidades. A diferencia de LIKE, aparentemente este constructo no usa índices.

Hemos tenido cierto éxito al utilizar Substring (que se traduce en SUBSTRING). El plan de ejecución es similar, pero en nuestro caso la consulta se ejecuta mucho más rápido.

Es otra "Estoy seguro de que será fijado en la FE 2" ... :-(

0

Puede utilizar un real como en el Enlace de Entidades con bastante facilidad

Esto es lo que se necesita para hacer labor que:

Añadir

<Function Name="String_Like" ReturnType="Edm.Boolean"> 
     <Parameter Name="searchingIn" Type="Edm.String" /> 
     <Parameter Name="lookingFor" Type="Edm.String" /> 
     <DefiningExpression> 
     searchingIn LIKE lookingFor 
     </DefiningExpression> 
    </Function> 

a su EDMX en esta etiqueta:

edmx: EDMX/edmx: Duración/edmx: ConceptualModels/Esquema

Asimismo, recuerda el espacio de nombres en el atributo <schema namespace="" />

A continuación, agregue una clase de extensión en el espacio de nombres arriba:

public static class Extensions 
{ 
    [EdmFunction("DocTrails3.Net.Database.Models", "String_Like")] 
    public static Boolean Like(this String searchingIn, String lookingFor) 
    { 
     throw new Exception("Not implemented"); 
    } 
} 

Este método de extensión ahora se asignará a la función EDMX.

Más información aquí: http://jendaperl.blogspot.be/2011/02/like-in-linq-to-entities.html

Cuestiones relacionadas