[ manda @ 06.11.2008. 14:48 ] @
Da li neko zna efikasan način (bez gomile koda i "da lepo izgleda") za OUTER JOIN-ovanje 2 tabele u C#.

Konkretno, hoću da spojim 2 tabele iz 2 različite baze (raznorodne, ORACLE + SQLServer), a bez linkovanja baza.

U pitanju je .NET 2.0, dakle bez LINQ-a (ako i sa ovim to može) ...

[ mmix @ 06.11.2008. 15:36 ] @
Bez LINQ-a nije bas jednostavno, ali nije ni previse komplikovano, moras samo da napravis relaciju izmedju dve tabele (mozes slobodno da punis dve tabele istog dataseta preko dva razlicita adaptera). onda uzmes iterator iz jedne i krenes redom, a uspostavljenu relaciju iskoristis da izvuces redove iz druge tabele, dakle dupli iterator. E sad koji iterator ce biti prvi i kako ce konkretno izgeldati te dve petlje zavisi od toga dal radis left, right ili full join. Generalno to je ono sto bi i LINQ uradio.


[ deerbeer @ 06.11.2008. 21:26 ] @
Citat:
mmix: Bez LINQ-a nije bas jednostavno, ali nije ni previse komplikovano, moras samo da napravis relaciju izmedju dve tabele (mozes slobodno da punis dve tabele istog dataseta preko dva razlicita adaptera). onda uzmes iterator iz jedne i krenes redom, a uspostavljenu relaciju iskoristis da izvuces redove iz druge tabele, dakle dupli iterator. E sad koji iterator ce biti prvi i kako ce konkretno izgeldati te dve petlje zavisi od toga dal radis left, right ili full join. Generalno to je ono sto bi i LINQ uradio.

Zar LINQ koristi samo klasican "table scan" bez ikakvog indeksiranja ?



[ mmix @ 07.11.2008. 08:54 ] @
Citat:
deerbeer: Zar LINQ koristi samo klasican "table scan" bez ikakvog indeksiranja ?


Jok, nema indeksiranja i radi se table scan, ali nije to bas tako vazno kao sto je kod db servera gde je IO vremenski najskuplji pa se postizu fenomenalne optimizacije kroz indeks, LINQ sve ionako radi u memoriji.
LINQ nije bas tolika magija, on je jednostavno fancy nacin da se odrade foreach petlje kroz extendere i lambdu i sta vise dosta je sporiji od najobicnije for petlje. Ali ako to 'progutamo, LINQ je dobar zato sto je kondenzovan u sorsu i mnogo jasniji za analiziranje.
[ manda @ 07.11.2008. 09:14 ] @
Ok, hvala Miks, mislio sam da ima neki trik bez "petljanja". Odradio sam ga

Čudno mi je to da je MS napravio nešto kao DataRelation, a da nije pritom dodao još poneku metodu, koja bi eventualno uradila ovo što sam ja kodirao, odnosno da vraća DataSet kao rezultat Joina dve client tabele, po zadatoj relaciji ...
[ mmix @ 07.11.2008. 10:20 ] @
To je zato sto posmatras dataset kao query engine, sto on nije, a ne kao temporary data storage, sto jeste.
[ deerbeer @ 07.11.2008. 13:27 ] @
Citat:
mmix: Jok, nema indeksiranja i radi se table scan, ali nije to bas tako vazno kao sto je kod db servera gde je IO vremenski najskuplji pa se postizu fenomenalne optimizacije kroz indeks, LINQ sve ionako radi u memoriji.
LINQ nije bas tolika magija, on je jednostavno fancy nacin da se odrade foreach petlje kroz extendere i lambdu i sta vise dosta je sporiji od najobicnije for petlje. Ali ako to 'progutamo, LINQ je dobar zato sto je kondenzovan u sorsu i mnogo jasniji za analiziranje.


A kakve su onda performanse LINQ-a sa table scanom ako imam 2 tabele sa po vise hiljada redova (da zanemarimo memoriju sada) ?
Zasto nisu iskoristili standardne .NET klase (SortedList,ArrayList,HashTable) za indeksiranje pa da programer bira nacin na koji ce da radi
inner join ili outer join u linq-u u zavisnosti od upita i broja tabela,redova itd .
Ustvari kako si i sam rekao sa Linq-om nisu pomerili DB engine ni malo od baze , vec su samo to lepo upakovali da bi kod bio pregledniji i citljiviji .





[ mmix @ 08.11.2008. 13:25 ] @
Pa to je malo diskutabilno, oko performansi. Kad uporedis sa disk-based bazom, poredjenje je deplasirano jer ce LINQ skoro uvek biti brzi (pod uslovom da se objekti i kolekcije ne page-uju u virtuelnu memoriju) jer i u najoptimizovanijim bazama u opstem slucaju indeks stranice moraju da se ucitaju sa diska da bi se pretrazile. Imaj u vidu da je RAM memorija takvih karakterisitka da je vreme pristupa bilo kom podatku preko bilo kog validnog pointera uvek isto i veoma brzo, i savim sigurno ti par hiljada redova nece praviti problem (zapravo trajace isto koliko i foreach petlja nad tom kolekcijom)

Ti mozes slobodno da koristis standardne .net strukture koje si pomenuo (a i neke druge pride) ali pretrazivanje svih ovih struktura je ekvivalentno table-scan i cak se i npr SortedArray bazira na table-scan pozivima delegata za poredjenje da bi odredio poziciju novog elementa u nizu. Nigde ti nemas mogucnost da indeksirano pretrazujes te strukture i inace (npr ako imas 1000 slucajno sortiranih brojeva od 200 do 500 ti ne mozes da dobijes pojavljivanje broja 366 bez punog scan-a cak ni u sortedarray).
Da bi to radilo sto ti hoces, LINQ bi morao pri svakoj LINQ komandi compile-time da izanalizira koji indeksi mu trebaju nad kolekcijama (a na osnovu predikata koju mogu biti proizvoljne kompleksnosti), da u runtime na osnovu pristiglih podataka izgradi indeks i da onda iskoristi taj indeks umesto IEnumerable<T> za pretrazivanje. Tri problema, prvo predikat moze biti nedeterministicki i u opstem slucaju ne moze se odrediti sta treba indeksirati niti se moze odrediti kod koji bi efikasno zamenio predikat (jedini nacin da se ovo resi bi bio ono sto SQL server radi, forsirati determinizam i ograniciti operacije u predikatima), drugo zauzima se dodatna memorija i trece ne dobija se nista sa stanovista performansi jer bi tokom gradjenja indeksa svejedno uradio pun table scan.


I pazi, ovo sto sam rekao za LINQ isto vazi i za recimo T-SQL, samo sto se to ne provaljuje tako lako. Npr, ostavimo performanse i indekse sa strane na sekund i uzmimo tabelu i cursor (bez where) nad njom i izvlacimo iz te tabele sve redove koji zadovoljavaju neki uslov (to je nas foreach table scan sa if uslovom), a nasuprot tome uzmi SELECT komandu sa tim istim uslovom (to je nas linq sa predikatom), oni efektivno oba rade istu stvar na isti nacin. Indeks je tu dodat da nas postedi bespotrebnih IO operacija, sta vise da na primer mozes iz T-SQL kurzora da radis b-tree pretrazivanje indeksa i performanse ova dva pristupa bi bile slicne.