Problem ograniczenie 2100 parametrów.
Przy problemie 2100 parametrów w LinqToSQL zrodziły się we mnie wątpliwości czy powiedzenie że każdy kod został już napisany i wystarczy go znaleźć jest prawdziwe.
Ale w czym rzecz. Komu by przyszło do głowy wpisywać przeszło dwa tysiące parametrów? Być może nie jest to wygodne rozwiązanie jeśli piszemy warunek
Name like 'a' Or Name like 'b'
Ale jeśli weźmiemy Contains (czyli po Sqlowemu IN) i np zestaw IDków lub GUIDów to już nie jest takie niedorzeczne.
Rozwiązanie znalazłam tutaj - jedyne znalezione rozwiązanie.
Idea
No przecież idealnie było by mieć nasz zbiór idków w jakiejś tabeli i się do niej join'ąć.
Problem
Listę idków mamy po stronie aplikacji a przecież zapytanie wykona się po stronie bazy danych więc listę trzeba przetransportować do bazy.
Rozwiązanie
Banał - wysłać listę do bazy, ale skoro nie możemy jako parametry to jak?
Stwórzmy jeden parametr typu XML i zapiszmy w tabelce tymczasowej - dzięki temu będziemy mieć się do czego join'ować z aplikacji.
Great. Rozwiązanie działa.
Ale
Okazało się że operacja dominująca w tym rozwiązaniu czyli Insert działa bardzo wolno. Praktycznie przy 2,5 tys rowków był to czas rzędu 20 sekund co praktycznie wyklucza rozwiązanie.
Dzięki wsparciu kolegi o wiedzy z SQLa znacznie większej niż moja, okazało się że wystarczy pominąć tabelkę tymczasową.
Oto pełne rozwiązanie.
Ale w czym rzecz. Komu by przyszło do głowy wpisywać przeszło dwa tysiące parametrów? Być może nie jest to wygodne rozwiązanie jeśli piszemy warunek
Name like 'a' Or Name like 'b'
Ale jeśli weźmiemy Contains (czyli po Sqlowemu IN) i np zestaw IDków lub GUIDów to już nie jest takie niedorzeczne.
private IQueryable GetList() { ContactDataContext cdc = new ContactDataContext(GlobalVariables.ConnectionString); cdc.ObjectTrackingEnabled = false; long[] ids = new long[]{1,2,...,2200}; var result = from cl in cldc.ContactLists where !cl.IsDeleted && ids.Contains(cl.ID) select cl; return result; }KaBum.
Rozwiązanie znalazłam tutaj - jedyne znalezione rozwiązanie.
Idea
No przecież idealnie było by mieć nasz zbiór idków w jakiejś tabeli i się do niej join'ąć.
Problem
Listę idków mamy po stronie aplikacji a przecież zapytanie wykona się po stronie bazy danych więc listę trzeba przetransportować do bazy.
Rozwiązanie
Banał - wysłać listę do bazy, ale skoro nie możemy jako parametry to jak?
Stwórzmy jeden parametr typu XML i zapiszmy w tabelce tymczasowej - dzięki temu będziemy mieć się do czego join'ować z aplikacji.
Great. Rozwiązanie działa.
Ale
Okazało się że operacja dominująca w tym rozwiązaniu czyli Insert działa bardzo wolno. Praktycznie przy 2,5 tys rowków był to czas rzędu 20 sekund co praktycznie wyklucza rozwiązanie.
Dzięki wsparciu kolegi o wiedzy z SQLa znacznie większej niż moja, okazało się że wystarczy pominąć tabelkę tymczasową.
Oto pełne rozwiązanie.
ALTER FUNCTION [dbo].[udf_ParseIDs] (@ids xml) RETURNS --@temp --TABLE(Id bigint) --BEGIN -- INSERT INTO @temp(id) -- ten insert był zbyt kosztowny! table as return( SELECT Id.value('.', 'bigint') as ID FROM @ids.nodes('/ArrayOfLong/long') list(id) --RETURN )
private IQueryable GetList() { ContactDataContext cdc = new ContactDataContext(GlobalVariables.ConnectionString); cdc.ObjectTrackingEnabled = false; long[] ids = new long[]{1,2,...,2200}; System.Xml.Linq.XElement serialized = GetIDsAsXml(ids); var result = from c in cdc.ContactLists join ids in cdc.udf_ParseIDsMediaPlan(serialized) on c.ID equals ids.ID where !c.IsDeleted && select c; return result; } ///Stworzenie elementu xml z listy longów public static XElement SerializeGuidList(IListA to już efekt przechwycony profilerem (troszkę przycięty xml):ids) { using (var sw = new System.IO.StringWriter()) { var guidArraySerializer = new XmlSerializer(typeof(long[])); guidArraySerializer.Serialize(sw, ids.ToArray()); using (var sr = new System.IO.StringReader(sw.ToString())) { return XElement.Load(sr); } } }
declare @p3 xml set @p3=convert(xml,N'Ciekawy problem i ciekawe rozwiązanie (i szybkie).') exec sp_executesql N'SELECT [t0].[ID], [t0].[CreatedBy], [t0].[CreateDate], [t0].[IsDeleted] FROM [dbo].[Contact] AS [t0] INNER JOIN [dbo].[udf_ParseIDs](@p0) AS [t1] ON ([t0].[ID]) = [t1].[Id] ORDER BY [t0].[ID]' ,N'@p0 xml',@p0=@p3 1 3 5 10 12 13 14 15 17 18 22 25 26 28 29 30 32 33 34 35 36 38 39 40 41 44 45 47 48 50 52 54 57 58 60 61 62 63 64 65 66 73 74 77 78 79 80 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
Komentarze
Prześlij komentarz