2009-02-23 17 views
6

Sto riscontrando alcuni problemi con linq alle entità nel framework di entità ado.net. Fondamentalmente quello che sto facendo è questo:linq alle entità generate sql

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

e questo si traduce a SQL come qualcosa di simile:

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

che va bene, ma la mia tabella ha milioni di record in modo tale corre molto lento. Che cosa ho bisogno per generare è qualcosa di simile:

WHERE Name LIKE @p + '%' 

sto cercato di alta e bassa e non riesco a trovare alcuna soluzione se non per utilizzare una stored procedure o l'uso Entity SQL ...

C'è qualche modo di farlo attraverso linq? Forse estendendo in qualche modo il linq al provider linq di entità, o in qualche modo intercettando l'albero dei comandi o la query generata?

+0

E 'questo genere di cose che mi rende molto relunctant di buttare via il mio livello di stored procedure a favore di tutto ciò che genera SQL. –

risposta

2

Wow, questo è un modo davvero bizzarro di farlo! Si noti che LINQ-to-SQL (in questo caso) utilizza LIKE @p0 + '%' ... molto dispari.

Quale provider EF (database) si sta utilizzando? Server SQL?

Come dici tu, una stored procedure sarà il lavoro, ma non si dovrebbe avere di farlo ... molto, molto strano ...

+0

Sì, sto utilizzando SQL Server 2005. Da quanto ho letto, LINQ to SQL fornisce una classe SqlMethods che espone funzioni SQL e operatori come LIKE ma non c'è nulla di simile in LINQ alle entità. Vai a ... –

4

Io non sono un esperto di SQL, ma indovinando che entrambe le sintassi:

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

e

WHERE Nome COME @p + '%'

comporterà una scansione della tabella o idealmente una scansione dell'indice. In conclusione, si esibiranno allo stesso modo. Ho verificato questo visualizzando i piani di esecuzione di seguito. In conclusione, è necessario rivedere lo schema del database o il modo in cui si sta eseguendo la ricerca. Questo non è un problema LINQ.

Una possibile area di miglioramento: assicurarsi di aver indicizzato la colonna su cui si sta effettuando la ricerca.

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

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

+1

Se hai un indice nella colonna Note/Name e la cardinalità non è troppo bassa, verrà usata su una query LIKE 'a%'. Non sono sicuro che Query Optimizer sarà in grado di utilizzare l'indice per un'operazione CAST (CHARINDEX()). –

+1

Ho un indice sulla colonna Nome del mio database. Il LIKE esegue una scansione dell'indice, l'SQL generato (CHARINDEX) esegue una scansione della tabella, motivo per cui richiede così tanto tempo. –

0

Is "lettera" a char? Se hai fatto una stringa, cosa succede?

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

È una stringa ... –

0

Ho provato ad utilizzare questa sintassi invece

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

Questa SQL viene generato

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

Forse questo è più efficiente?

+0

Sì, ci ho provato anche io ... Penso che sia andato avanti lo stesso. –

1

Questo è un known issue con Linq alle entità. A differenza di LIKE, a quanto pare questo costrutto non usa indici.

Abbiamo avuto successo usando la sottostringa (che si traduce in SUBSTRING). Il piano di esecuzione è simile, ma nel nostro caso la query viene eseguita molto più rapidamente.

E 'un altro "Sono sicuro che sarà fissato in EF 2" ... :-(

0

È possibile utilizzare un vero e proprio come nel link di entità abbastanza facilmente

Ecco ciò che è necessario per rendere esso opera:

Aggiungi

<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> 

al vostro EDMX in questo tag:

edmx: EDMX/edmx: Runtime/edmx: ConceptualModels/Schema

Ricorda anche lo spazio dei nomi dell'attributo <schema namespace="" />

Quindi aggiungere una classe di estensione nello spazio dei nomi di cui sopra:

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"); 
    } 
} 

Questo metodo di estensione verrà ora associato alla funzione EDMX.

Maggiori informazioni qui: http://jendaperl.blogspot.be/2011/02/like-in-linq-to-entities.html

Problemi correlati