in

mscommunity.net

Interactive mscommunity.net online activities

data.hr

veljača 2008 - Posts

  • DLinqy-thingy, Part One

    At last, I found some spare time to start playing with that Linq2SQL thing. Installed VS2008 RTM. fired it up, created a new C# console project, added a reference to System.Data.Linq, created the appropriate .dbml to Northwind database, and typed in the following code, more or less copied from the ScottGu blog (http://weblogs.asp.net/scottgu/archive/2007/05/19/using-linq-to-sql-part-1.aspx):

                northwindDataContext db = new northwindDataContext();

                Product product = db.Products.Single(p => p.ProductName == "Flotemysost");
                product.UnitPrice = 99;
                product.UnitsInStock = 5;

                db.SubmitChanges();

     

    Fired up the SQL Server profiler to capture what's really happening, and pressed F5.

    And here's what was in the profiler trace:

    exec sp_executesql N'SELECT [t0].[ProductID], [t0].[ProductName], [t0].[SupplierID], [t0].[CategoryID], [t0].[QuantityPerUnit], [t0].[UnitPrice], [t0].[UnitsInStock], [t0].[UnitsOnOrder], [t0].[ReorderLevel], [t0].[Discontinued]
    FROM [dbo].[Products] AS [t0]
    WHERE [t0].[ProductName] = @p0',N'@p0 nvarchar(11)',@p0=N'Flotemysost'

    exec sp_executesql N'UPDATE [dbo].[Products]
    SET [UnitPrice] = @p9, [UnitsInStock] = @p10
    WHERE ([ProductID] = @p0) AND ([ProductName] = @p1) AND ([SupplierID] = @p2) AND ([CategoryID] = @p3) AND ([QuantityPerUnit] = @p4) AND ([UnitPrice] = @p5) AND ([UnitsInStock] = @p6) AND ([UnitsOnOrder] = @p7) AND ([ReorderLevel] = @p8) AND (NOT ([Discontinued] = 1))',
    N'@p0 int,@p1 nvarchar(11),@p2 int,@p3 int,@p4 nvarchar(16),@p5 money,@p6 smallint,@p7 smallint,@p8 smallint,@p9 money,@p10 smallint',
    @p0=71,@p1=N'Flotemysost',@p2=15,@p3=4,@p4=N'10 - 500 g pkgs.',@p5=$21.5000,@p6=26,@p7=0,@p8=0,@p9=$99.0000,@p10=5


    What can we say about the SELECT statement? It's simple, but there are at least two things wrong. First, notice that the SELECT list incudes *all* columns from the Products table, although we had no intention of using them all. I agree, Linq has no way of guessing what we're going to need and what not, but anyway it's way too easy to type in an equivalent of "select *" without being aware of it. Second, the @p0 parameter is nvarchar(11). It's just plain stupid, IMHO. Remember, we have the data model in the project, and the Linq engine knows that the ProductName column's datatype is nvarchar(40). Nevertheless, it decided to simply count the characters from the "Flotemysost" const. Why, oh why? OK, so we will get the different query plan depending on the value passed to the query. Not exactly good for the plan reuse, right?

    And what to say about the "optimistic" UPDATE statement? Well, it's just plain wrong.. Please -- never, never, never update the data without using a stored procedure. Please :)

    TBC.

    Dean

    Posted vlj 21 2008, 07:06 by dvitner with 3 comment(s)
    Filed under:
  • I unikifikacija ima granice..

    OK, long time no see.. :))

    Svi znamo da mozemo kreirati clustered indeks (CI) na (skoro) bilo kojem subsetu kolona iz tablice. Također, svi znamo da možemo kreirati nonclustered indekse (NCI) na (skoro) bilo kojem subsetu kolona iz tablice, manje-više neograničen broj njih.

    Kod upita koje radimo na tablicu, kada access path prema podacima koji izabere SQL Server optimizer uključuje NCI, i ako taj NCI nije "covering" za taj upit, SQL Server mora pročitati ostale kolone koje mu trebaju tako da pristupi clustered indeksu*, ako ga imamo. Naravno, u slucaju da nemamo CI na tabli, prica se mijenja, i ostatku podataka se pristupa preko row identifikatora (RID). No, zadržimo se na ovom slučaju kad radimo seek na NCI na tabli s CI.

    Svaki red u NCI, pored vrijednosni kolona koje čine indeks, sadrži i vrijednost CI, pomoću kojeg onda SQL Server pronalazi potreban red u CI, tj samoj tabli (jer CI nije nista drugo nego tabla, s indeksnom strukturom iznad sebe). Da bi se to moglo ostvariti, tj da bi SQL Server mogao locirati baš taj određeni red u tabli/CI, očito je da vrijednost CI mora biti unique za tablu. S druge strane, CI se može bez problema kreirati i nad non-unique kolonom, dakle može sadržavati iste vrijednosti indeksnih kolona za različite redove. Kako je onda moguće pronaći odgovarajući red iz NCI u CI kad identifikator preko kojeg se to radi nije unique?

    Odgovor je prilično jednostavan: ako imamo non-unique CI, SQL Server će dodati još jednu kolonu u CI (tzv. uniquifier) i zatim u NCI prenositi ne samo vrijednost CI nego i taj uniquifier. Dakle, na umjetan način će "unikificirati" vrijednost clustered indeksa (da li je ovdje pravilno reći "unikificirati" ili "unificirati"?). Ta "unikifikator" kolona se ne može vidjeti kroz SELECT, nego samo korištenjem DBCC PAGE naredbe. Pored toga, ona je int tipa. Pa sad, ako imate CI na koloni koja ima vise od 2^31 (sasvim precizno, ne 2^31 nego 2.147.200.030) neke iste (kombinacije) vrijednosti u CI, onda imate problem, ne? I osobno, rekao bih da ga u tom slučaju i zaslužujete :))

    Pozdrav, čujemo se.

    Dean


    *) Ne, ne mora nužno biti CI, ako postoji NCI koji je uži i kojem je pristup jeftiniji i preko kojeg se može zadovoljiti upit, optimizer se može odlučiti i za taj NCI. Obećavam post u kojem ću ovo demonstrirati.

    Posted vlj 12 2008, 08:21 by dvitner with 1 comment(s)
    Filed under:
Powered by Community Server (Commercial Edition), by Telligent Systems