Soci (Soczó Zsolt) szakmai blogja

2008.05.28.

Mi az a Dynamic Data?

Filed under: .NET,Adatbázisok,ADO.NET,ASP.NET,C#,SQL Server,Szakmai élet — Soczó Zsolt @ 07:24

5 perces kis videó a témáról.

Valami olyasmi cucc ez, amivel rendkívül gyorsan össze lehet rakni CRUD jellegű adatkezelő website-okat, de teljesen testreszabható módon, template alapon, nem sima kódgenerálással. Érdekes megoldás, de nem tudom mennyire lesz majd használható.

2008.05.08.

Konferenciaanyagok

Filed under: Adatbázisok,ADO.NET,SQL Server,SQL Server 2008,Szakmai élet — Soczó Zsolt @ 07:01

Tegnap lement a konferencia, én ahogy haladtunk előre egyre jobban feloldódtam és jobban éreztem magam. Egyből a délutáni előadással kellett volna kezdenem. :)

Ahogy már írtam korábban sok anyag készült, ami nem került bele a konf folyamába, ezeket hamarosan elkezdem kirakni ide.

Most első lépésként a két előadásom pptjét töltöttem fel.

Update: office 2003 ppt verzió

2008.02.12.

LINQ vs. SQL teljesítmény

Az előző cikkemmel csak az volt a célom, hogy megmutassam, hogyan lehet megírni ugyanazt a lekérdezést kétféle módon, a teljesítményüket nem is vizsgátam, mivel érzésre egyik se volt túl lassú.

Laci kommentjében a teljesítmény kérdésre hívta fel a figyelmem, hát megnéztem, mi itt a helyzet. Nos, megúszta a LINQ, pedig nem akartam neki reklámot csinálni. Pontosan ugyanolyan teljesítményű lett a két megoldás, ami nem csoda, hisz pontosan ugyanaz az SQL végrehajtási tervet eredményezik! Egyetlen különbség, hogy a sorszámozást LINQ esetén csak procedurálisan tudtam megcsinálni, így a LINQ sql-es kódjában az nem szerepel, de ennek költsége nem is jelent meg a tiszta SQL megoldás végrehajtási tervében, annyira kicsi.

A lényeg tehát, hogy a LINQ nem feltétlenül lassú, sőt, teljesen egyenértékű lehet a hagyományos SQL-es megoldással. De miért is lenne más? Hisz egyszerűen arról van szó, hogy másképp írom le ugyanazt a specifikációt, az egész hatékonysága azon múlik, mennyire okos a LINQ to SQL sqlgenerátora. A jelek szerint egyszerűbb lekérdezésekre tökéletes.

Aki nem hiszi amit írok, nézze meg az alábbi képet (rákattintva nagyban).

LINQ vs SQL teljesítmény

2008.02.11.

LINQ vs. SQL

Filed under: .NET,Adatbázisok,ADO.NET,C#,Linq,SQL Server,SQL Server 2005,Szakmai élet — Soczó Zsolt @ 23:13

Melyik a szimpatikusabb?

select bucid, score, countMatchedEcid, ROW_NUMBER() 
OVER(ORDER BY score DESC) AS 'rank' 
from (
select 
b.ucid as bucid,
a.ucid as aucid, 
sum(w.weight) as score,    
count(*) as countMatchedEcid
from EcidNameValueSummary a, 
genecidparts b, 
weights w 
where a.id=b.id 
and a.value=b.value 
and a.ucid!=b.ucid 
and w.id=a.id 
and w.allowed=1 
and w.limit>=a.countEcids 
and a.ucid=@ucid 
group by b.ucid, a.ucid
) as hits
var matchQuery = from t in
    (from a in c.EcidNameValueSummaries
    join b in c.genecidparts
    on a.id equals b.id
    join w in c.Weights
    on a.id equals w.id
    where w.allowed == 1
    && w.limit >= a.countEcids
    && a.value == b.value
    && a.ucid != b.ucid
    && a.ucid == ucid
    select new
    {
        bucid = b.ucid,
        aucid = a.ucid,
        score = w.weight1
    })
group t by t.bucid into g
orderby g.Sum(e => e.score) descending
select new RankEntity
{
    Ucid = g.Key,
    Score = g.Sum(e => e.score) ?? 0,
    CountMatched = g.Count(),
    Rank = 0
};


BindingListCollection<RankEntity> ranks = 
new BindingListCollection<RankEntity>();
int i = 1;
//It would be cool to do this with linq, but...
foreach (RankEntity e in matchQuery)
{
    e.Rank = i++;
    ranks.Add(e);
}
return ranks;

És emellett, a ROW_NUMBER-t át tudná nekem valaki fordítani LINQ-ra?

2008.01.23.

DMF, SMO, LINQ példácska

Filed under: .NET,Adatbázisok,ADO.NET,C#,Linq,SQL Server 2008,Szakmai élet — Soczó Zsolt @ 18:37

Nézegettem az SQL 2008 könyvet, és az ottani példa alapján kedvem támadt kipróbálni a LINQ-t. Tetszik, nem tudom valódi appokban tényleg jó-e, de babrálni vele érdekes.

using System;
using System.Linq;
using Microsoft.SqlServer.Management.Dmf;

class Program
{
    static void Main(string[] args)
    {
        ConsoleColor origColor = Console.ForegroundColor;

        var fc = from f in PolicyStore.Facets
                 orderby f.DisplayName
                 select f;
        foreach (var fi in fc)
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("Facet {0}:", fi.DisplayName);
            Console.ForegroundColor = origColor;

            var props = from f in fi.FacetProperties
                        orderby f.Name
                        select f;
            int i = 0;
            foreach (var pi in props)
            {
                Console.Write(pi.Name);
                if (i++ > 0)
                    Console.Write(", ");
            }
            Console.WriteLine();
            Console.WriteLine("-----------------------------------");
        }
    }
}

Állítólag ez a DMF nagy durranás az adminoknak, tessék örülni neki és olvasni az ingyenes fejezetet.

2007.12.13.

Tapasztaltok egy 35ezer tranzakció/mp-es rendszer implementációjából

Filed under: .NET,Adatbázisok,ADO.NET,SQL Server 2005,Szakmai élet — Soczó Zsolt @ 19:54

Na, nem én csináltam, sajnos nálunk nem nagyon van ilyen, bár, ha tudtok róla, jelezzétek. Mobilosoknál talán van valami hasonló terheltségű db, de az Oracle.

Szóval, nagyon-nagyon jó post a témában, pár meglepő fordulattal, pl.

Néha nem a legszebb megoldás a legjobb:
“When developing the upsert proc prior to tuning the indexes, I first trusted that the If Exists(Select…) line would fire for any item and would prohibit duplicates. Nada. In a short time there were thousands of duplicates because the same item would hit the upsert at the same millisecond and both transactions would see a not exists and perform the insert. After much testing the solution was to use the unique index, catch the error, and retry allowing the transaction to see the row and perform an update instead an insert.”

A CLR implementáció bukása, talán az interop költségek miatt?

“This app requires that several hundred “items” are passed into the stored procedure for processing as a set. I chose to input the data as comma delimited VarChar(max), originally using Erland’s iterative string2set function to parse string into a set inside the proc. It worked well enough. The plan was to substitute a CLR function near the end of development. When the time came, the CLR function ran blazingly fast on my notebook, but under stress it was painfully sloooooow. I didn’t understand at all why. This is exactly what we were told by Microsoft the CLR was for. Pass string data in, manipulate it, pass it back – no data access – sounds great right? In a few emails to my friend Adam, he told me he had the same issues a while back and the CLR simply could keep up with the marshalling of the VarChar(max).”

Stb. Nagyon jó cikk.

SQL Server 2008 újdonságok 5. – streaming adatok kezelése kliensoldalról

Filed under: .NET,Adatbázisok,ADO.NET,SQL Server,SQL Server 2008,Szakmai élet — Soczó Zsolt @ 12:32

Az előző részben elkészült a táblánk, ami streaming adatokat tud tárolni. Itt az ideje pár fotót beleszórni az adatbázisba (illetve a fájlrendszerbe).

Az adatokat beküldhetjük SQL parancsként is, a megszokott TDS csatornát felhasználva. Azonban pont azért rakták ki filerendszerbe ezeket a nagy adatokat, hogy NE TDS-en keresztül, hanem SMB-vel, a windows file megosztásán keresztül érjük el őket. Ez kicsit szokatlan lesz, hisz lesz ugyan SQL INSERT, de lesz sima fájlkezelés is a megoldásban. Mondom, menne sima SQL-lel is, de az nem lenne túl hatékony.

No, a megoldás elég bizarr lesz. Nincs ugyanis managed felület az adatok kezelésére! Legalábbis most, 2007 végén nincs. Natív API van, azt lehet rugdosni .NET-ből, interopon keresztül, ha kell.

A megoldás menete vázlatosan a következő.
1. Hozzákapcsolódunk a szerverhez SqlConnectionnel, tranzakciót indítunk, hozzárendeljük a használandó SqlCommandunkhoz. Eddig semmi új.

2. Beszúrjuk a stream metaadatait, a sima adatokat, egy insert-tel, hagyományos módon, ADO.NET-tel.

insert into Kepek (Id, Name, Photo) values (@Id, @Name, cast ('' as varbinary(max)))

A furcsa üres stringet kasztoló izé azért van a parancsban, hogy megágyazzunk az adatoknak a filerendszerben. E nélkül, ha null maradna az oszlop értéke nem jönne létre fájl a diszken, így a következő lépés se menne.

3. Visszaolvassuk a sorunkhoz tartozó stream mint fájl elérési útját és egy tranzakció azonosítót, ez kell majd a következő lépésben. Mindkettőre van egy új függvény illetve metódus (kiemelve).

select Photo.<strong>PathName()</strong> PathName, <strong>get_filestream_transaction_context()</strong> TranCtx from Kepek where Id = @Id

4. Most jön a bizarrabb rész. Kapunk egy natív függvényt, azzal lehet megnyitni trazakcionálisan a streamünket mint fájlt: OpenSqlFilestream. Mivel ő natív cucc, kell hozzá interop deklaráció, kb. így:

[DllImport(“sqlncli10.dll”, SetLastError = true, CharSet = CharSet.Unicode)]
public static extern SafeFileHandle OpenSqlFilestream(
string FilestreamPath,
UInt32 DesiredAccess,
UInt32 OpenOptions,
byte[] FilestreamTransactionContext,
UInt32 FilestreamTransactionContextLength,
LARGE_INTEGER_SQL AllocationSize
);

[StructLayout(LayoutKind.Sequential)]
public struct LARGE_INTEGER_SQL
{
public Int64 QuadPart;
public LARGE_INTEGER_SQL(Int64 quadPart) { QuadPart = quadPart; }
}

Ronda, de az interop már csak ilyen. Örüljünk, hogy működik. Vagy tessék használni C++-t.

A paraméterek értékét az előző pont select-je szolgáltatja, amit egy reader-rel érek el:

byte[] tranCtx = (byte[])reader[“TranCtx”];

SafeFileHandle h = OpenSqlFilestream(
(string)reader[“PathName”],
DESIRED_ACCESS_WRITE,
0,
tranCtx,
(uint)tranCtx.Length,
new LARGE_INTEGER_SQL(0))

Kapunk egy szép Handle-t, amit az interop réteg egyből be is csomagol egy SafeFileHandle-be, mert azt úgy illik (aki nem hallott a safehandle-ökről, most álljon meg, és sürgősen olvasson utána, nem hosszú a cikk).

5. A Win32 handle jó dolog, de nem kezdünk neki WriteFile API-val baromkodni, hanem kihasználjuk, hogy a FileStream könnyen összebarátkozik valahonnan szerzett File Handle-ökkel:

FileStream fsWrite = new FileStream(h, FileAccess.Write)

6. Most már csak írni kell bőszen az fsWrite-ba. Figyeljük meg, hogy ez a lényege pont a streaming elérésnek, hogy nem összerakunk egy 34 GByte-os ojjektumot, mondjuk byte[]-öt, és odavágjuk a szervenek (eleve, a kliens belehalna ebbe), hanem apránként lapátoljuk be az adatokat. Ráérősen, öregesen. Valahogy így pl.

int readed;
byte[] buff = new byte[4096];
do
{
readed = fsRead.Read(buff, 0, buff.Length);
fsWrite.Write(buff, 0, readed);
}
while (readed > 0);

Az fsRead a helyi képre van megnyitva, amit betolunk a szervernek. Teccik látni, kicsi kis darabkákban megy be a hatalmas kép.

Számos kérdés, mint izolációs szint, mi látszik ebből a fájlrendszerben, kihasználja-e a tranzakcionális NTFS-t, stb. merül még fel, ezekkel a következő részben foglalkozok.

Zárásul berakom a teljes kódot, élvezzétek. :)

(Tud valaki valami normális, kész, szép wordpress theme-et, ami úgy van belőve, hogy olyan szélesen formázza meg a szöveget, mint amekkora az ablak mérete? Elkezdtem átszabni ezt a Kubrick theme-et, de ez halál, nekem bonyolult megérteni és átírni. A kódok miatt kellene.)

using System;
using System.Data.SqlClient;
using System.IO;
using System.Data;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

namespace FSTest
{
class Program
{
static void Main(string[] args)
{
SqlTransaction tran = null;
try
{
using (SqlConnection conn = new SqlConnection(
@”Data Source=.\sql2008;Initial Catalog=FSTeszt;Integrated Security=true;”))
{
using (SqlCommand cmd = new SqlCommand())
{
conn.Open();
tran = conn.BeginTransaction();
cmd.Connection = conn;
cmd.Transaction = tran;

foreach (string f in Directory.GetFiles(@”E:\ment\kepek\Hivatni”, “*.jpg”))
{
//Kép alapadatok beszúrása
cmd.CommandText = @”insert into Kepek (Id, Name, Photo)
values (@Id, @Name, CAST (” as varbinary(max)))”;
cmd.Parameters.Clear();
cmd.Parameters.Add(“@Name”, SqlDbType.NVarChar).Value = Path.GetFileName(f);
Guid id = Guid.NewGuid();
cmd.Parameters.Add(“@Id”, SqlDbType.UniqueIdentifier).Value = id;
cmd.ExecuteNonQuery();

//Maga a kép mentése mint streaming adat
cmd.CommandText = @”select Photo.PathName() PathName,
get_filestream_transaction_context() TranCtx from Kepek where Id = @Id”;
using (SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
{
if (reader.Read())
{
byte[] tranCtx = (byte[])reader[“TranCtx”];

using (SafeFileHandle h = OpenSqlFilestream(
(string)reader[“PathName”],
DESIRED_ACCESS_WRITE,
0,
tranCtx,
(uint)tranCtx.Length,
new LARGE_INTEGER_SQL(0)))
{

if (!h.IsInvalid)
{
using (FileStream fsWrite = new FileStream(h, FileAccess.Write))
using (FileStream fsRead = File.OpenRead(f))
{
int readed;
byte[] buff = new byte[4096];
do
{
readed = fsRead.Read(buff, 0, buff.Length);
fsWrite.Write(buff, 0, readed);
}
while (readed > 0);
}
}
else
{
int errno = Marshal.GetLastWin32Error();
Console.WriteLine(errno);
Environment.Exit(-1);
}
}
}
}

}
}
tran.Commit();
}
}
catch (Exception e)
{
tran.Rollback();
Console.WriteLine(e);
}
}

public const UInt32 DESIRED_ACCESS_READ = 0x00000000;
public const UInt32 DESIRED_ACCESS_WRITE = 0x00000001;
public const UInt32 DESIRED_ACCESS_READWRITE = 0x00000002;

[DllImport(“sqlncli10.dll”, SetLastError = true, CharSet = CharSet.Unicode)]
public static extern SafeFileHandle OpenSqlFilestream(
string FilestreamPath,
UInt32 DesiredAccess,
UInt32 OpenOptions,
byte[] FilestreamTransactionContext,
UInt32 FilestreamTransactionContextLength,
LARGE_INTEGER_SQL AllocationSize
);

[StructLayout(LayoutKind.Sequential)]
public struct LARGE_INTEGER_SQL
{
public Int64 QuadPart;
public LARGE_INTEGER_SQL(Int64 quadPart) { QuadPart = quadPart; }
}

[DllImport(“kernel32.dll”)]
private extern static void CloseHandle(IntPtr handle);
}
}

2007.12.10.

SQL Server 2008 újdonságok 2. – Dátum típusok

Filed under: .NET,Adatbázisok,ADO.NET,SQL Server,SQL Server 2008,Szakmai élet — Soczó Zsolt @ 14:16

Hát igen, már az SQL Server 2005-ben is úgy volt, hogy lesz DATE és TIME típus. Meg is írták CLR típusként, aztán kidobták, nem illett bele a képbe, kilökte azt a gazdatest.

Most, 2008-ban újra nekiláttak, ezúttal sikerrel (ha élcelődni szeretnék, márpedig miért ne, 10 éve kellett volna ezt meglépni).

No, mi a bajunk a DATETIME és SMALLDATETIME típusokkal.
1. Kicsi az értékkészletünk, 1753 előtt is volt már világ.
2. Kicsi a pontosságuk, a pontosabbnak, a DATETIME-nak is 3 ms a felbontása.
3. Nem kezelnek időzónát.
4. Nincs külön csak dátum és csak idő tároló típus. Eleve, sokszor csak az egyik kell, pl. napra kerekített dátum tárolás, és ilyenkor nem csak könnyebb kezelni a külön tárolt darabokat, de hely se kell neki annyi.

No, lássuk, mit kapunk hát a 2008-ban?

1. DATE típus. 0001-01-01 és 9999-12-31 között működik, és csak 3 byte-ot eszik. Nyilván nap a felbontása.

2. TIME típus. Maximum 100ns felbontású, lehet szabályozni, mennyire legyen pontos. TIME(7) pl. 100ns-os, és 5 byte-os igényel. TIME(0) csak 3 byte, cserébe csak század mp-ig pontos. Még egy példaként TIME(4) 4 byte, és 3-4 digitig pontos (kb. ms-os felbontás).

3. DATETIME2. Az előző kettő hibridje, 6-8 byte kell neki, nyilván az idő tag pontosságától függően.

4. DATETIMEOFFSET típus. A DATETIME2 időzónával kiegészített változata. Stringként így szoktuk leírni: ‘2007-05-08 12:35:29.1234567+12:15, azaz plusz 12 óra 15 perc az időeltolódás.

Ami izgi kérdés, hogyan látszanak ezek a típusok ADO.NET-ből, ráadásul, mit látunk 2.0-ból, és mit a 3.5-ből, ami már fel van készítve az új típusokra?

Először nézzük a 3.5-öt. Az SqlDbType-ban készült négy új érték:

SqlDbType.Date
SqlDbType.Time
SqlDbType.DateTime2
SqlDbType.DateTimeOffSet

Az SQL DATE és DATETIME2 a CLR megszokott DateTime típusára képződik le. A TIME a TimeSpanra, a DATETIMEOFFSET pedig egy új CLR típusra a System.DateTimeOffsetre alakul át. Bővebben itt.

Ez alapján a .NET fw. 2.0 SP1 és 3.0 SP1 is tartalmazza a DateTimeOffset-et. Furcsa mód, reflectorral megnézve a 3.5-ös mscorlibet nem találtam benne ezt az új típust. VS 2008 látja. A 2.0-s mscorlib-ben látja. Bugos a reflector?

Régebbi kliensek szerintem byte[]-ként látják az DateTimeOffSet-et, de most nem tudom tesztelni.

2007.12.07.

SQL Server 2008 újdonságok 1. – Tábla típusú paraméterek

Filed under: Adatbázisok,ADO.NET,SQL Server,SQL Server 2008,Szakmai élet — Soczó Zsolt @ 10:32

A következő néhány hónapban minden nap rászánok kevés időt, hogy az SQL Server 2008-ba belemélyedjek, közben igyekszem dokumentálni a blogomban az újdonságokat. A cikkekben semmilyen tematika vagy sorrend nem lesz, egyszerűen csak magozok az elém kerülő újdonságokból.

Az első új fícsör a tábla típusú paraméterátadás. Ez finom dolog lesz, nem kell stringekbe serializálni a paramétereket, nem kell xmlt használni, hanem egyszerűen át lehet passzintani egy tábla típusú változót a hívott eljárásnak.

Ehhez a CREATE TYPE került felokosításra, ami már nem csak aliasokat tud (SQL Server 7), vagy CLR típusokat (SQL Server 2000), hanem tábla típusokat is (SQL Server 2008). Pl.

CREATE TYPE LocationTableType AS TABLE
(
LocationName VARCHAR(50),
CostRate INT
)

Aztán paraméterként így lehet használni mondjuk spben:

CREATE PROC Ize
(
@par LocationTableType
)

Komplett példa itt látható.

Belül mint egy sima táblát lehet joinolni, stb.

Miért is jó a BOL szerint:

Do not acquire locks for the initial population of data from a client.
Do not cause a statement to recompile.
Provide a simple programming model.
Enable you to include complex business logic in a single routine.
Reduce round trips to the server.
Can have a table structure of different cardinality.
Are strongly typed.
Enable the client to specify sort order and unique keys.

Az első pont mindjárt kíváncsivá tett, hogy lehet ADO.NET-ből feltölteni a tábla paramétert. Zseniálisan egyszerűen, sima DataTable-t kell feltölteni, és már mehet is be a szervernek. Állat.

2007.04.29.

MS Entity Framework – hej, ráérünk arra még

Filed under: .NET,ADO.NET,Szakmai élet — Soczó Zsolt @ 13:29

Emlékszem, az egész O/R mapper ügylet még 2002 táján kezdődött. Titkos sugdolódzások voltak: az ms O/R mappert ír (ObjectSpaces), belerakja ingyen a .NET-be, annyi a third party mapper íróknak. Aztán párszor még beígérték a terméket, fw. 2.0, SQL 2005, Vista, most a fw. 3.5. De ez se jött be.

Frans Bouma szerint egyszerű üzleti érdekek miatt tolták el a shipet.

Majd 2008-ban találkozunk vele újra. :)

2006.09.29.

Jó LINQ forrás

Filed under: .NET,Adatbázisok,ADO.NET,C#,Szakmai élet — Soczó Zsolt @ 14:42

Betárazom magamnak is tanulásra.

2006.09.27.

ADO.NET vNext

Filed under: ADO.NET,Szakmai élet — Soczó Zsolt @ 18:37

Nemrég írtam róla némi infót, ebben a blogban sokkal több mindenről lehet olvasni a “jövőről”.

« Older Posts

Powered by WordPress