2009-02-23 14 views
6

Mam pewne problemy z linq do podmiotów w ramach encji ado.net. W zasadzie to, co robię jest taka:linq do podmiotów generowanych sql

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

i ten dostaje tłumaczone do SQL jako coś w rodzaju:

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

który jest w porządku, ale moja tabela ma miliony rekordów, więc to działa bardzo wolno. Co muszę go wygenerować jest coś takiego jak:

WHERE Name LIKE @p + '%' 

mam przeszukiwane wysokiego i niskiego i nie można znaleźć żadnych rozwiązań wyjątkiem użyć procedury przechowywanej lub użyj podmiotu SQL ...

Czy istnieje sposób zrobić to za pomocą linq? Być może w jakiś sposób rozszerzając linq na podmioty linq provider, lub w jakiś sposób przechwytując drzewo poleceń lub wygenerowane zapytanie?

+0

Jest to rodzaj rzeczy, które sprawia, że ​​bardzo relunctant wyrzucić moje procedury przechowywanej warstwę na rzecz wszystkiego, co generuje SQL. –

Odpowiedz

2

Wow, to naprawdę dziwaczny sposób robienia tego! Zauważ, że LINQ-SQL (w tym przypadku) używa LIKE @p0 + '%' ... bardzo dziwne.

Jakiego dostawcy EF (bazy danych) używasz? Serwer SQL?

jak mówisz, to procedura przechowywana będzie zadanie, ale nie powinien mieć to zrobić ... bardzo, bardzo dziwne ...

+0

Tak Używam programu SQL Server 2005. Z tego, co przeczytałem, LINQ to SQL udostępnia klasę SqlMethods, która udostępnia funkcje SQL i operatory takie jak LIKE, ale nie ma czegoś takiego w LINQ do Entities. Idź do figury ... –

4

Nie jestem ekspertem, ale domyślam się, że SQL obu składni:

GDZIE (wlewka (CHARINDEX (@p [Extent1] [nazwa]) int)). = 1

i

gdzie nazwa JAK @p + '%'

spowoduje albo skanowanie tabeli, albo idealnie skanowanie indeksu. Podsumowując, wykonają to samo. Zweryfikowałem to, przeglądając poniższe plany wykonania. Podsumowując, musisz ponownie przemyśleć schemat bazy danych lub sposób przeprowadzania wyszukiwania. To nie jest kwestia LINQ.

Jeden z możliwych obszarów wymagających poprawy: upewnij się, że zaindeksowałeś kolumnę, której szukasz.

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

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

+1

Pod warunkiem, że masz indeks w kolumnie Note/Name, a liczebność nie jest zbyt niska, zostanie użyta w zapytaniu LIKE "a%". Nie jestem pewien, czy optymalizator zapytań będzie mógł użyć indeksu dla operacji CAST (CHARINDEX()). –

+1

Mam indeks w kolumnie Nazwa mojej bazy danych. LIKE wykonuje skanowanie indeksu, wygenerowany SQL (CHARINDEX) wykonuje skanowanie tabeli, dlatego zajmuje tak dużo czasu. –

0

Czy "litera" char? Jeśli zrobiłeś ciąg, co się dzieje?

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

To jest ciąg ... –

0

Próbowałem za pomocą tej składni zamiast

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

to SQL jest generowany

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

Może to jest bardziej wydajny?

+0

Tak, próbowałem też ... Myślę, że to działa tak samo. –

1

To jest known issue z Linq do Entities. W przeciwieństwie do LIKE, najwyraźniej ta konstrukcja nie używa indeksów.

Odnieśliśmy sukces za pomocą podłańcucha (co przekłada się na SUBSTRING). Plan wykonania jest podobny, ale w naszym przypadku zapytanie wykonuje się znacznie szybciej.

To kolejny „Jestem pewien, że zostanie on rozwiązany w EF 2” ... :-(

0

Można użyć prawdziwego jak w Link do Podmiotów dość łatwo

Oto, co jest potrzebne, aby praca to:

Dodaj

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

do EDMX w tym tagu:

edmx: Edmx/edmx: Runtime/edmx: ConceptualModels/Schema

Pamiętaj również przestrzeń nazw w atrybucie <schema namespace="" />

Następnie dodać klasę przedłużacza w powyższym nazw:

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

Ta metoda rozszerzenia zostanie teraz odwzorowana na funkcję EDMX.

Więcej informacji tutaj: http://jendaperl.blogspot.be/2011/02/like-in-linq-to-entities.html

Powiązane problemy