Avatar billede misbruger Nybegynder
06. juli 2006 - 15:26 Der er 15 kommentarer og
1 løsning

Alt for mange joins i view

Jeg har følgende query, hvor outputtet er godt nok, men jeg har brug for en lidt mere intelligent måde at gøre det på...
Skal bruges til et View

SELECT P.indeks, PD1.val, PD2.val, PD3.val, PD4.val, PD5.val, PD6.val, PD7.val, PD10.val, PD16.val
FROM Products P
    LEFT JOIN ProductData PD4 ON P.indeks = PD4.product AND PD4.dataType = 4
    LEFT JOIN ProductData PD7 ON P.indeks = PD7.product AND PD7.dataType = 7
    LEFT JOIN ProductData PD6 ON P.indeks = PD6.product AND PD6.dataType = 6
    LEFT JOIN ProductData PD10 ON P.indeks = PD10.product AND PD10.dataType = 10
    LEFT JOIN ProductData PD16 ON P.indeks = PD16.product AND PD16.dataType = 16
    LEFT JOIN ProductData PD1 ON P.indeks = PD1.product AND PD1.dataType = 1
    LEFT JOIN ProductData PD5 ON P.indeks = PD5.product AND PD5.dataType = 5
    LEFT JOIN ProductData PD3 ON P.indeks = PD3.product AND PD3.dataType = 3
    LEFT JOIN ProductData PD2 ON P.indeks = PD2.product AND PD2.dataType = 2

Bemærk at alle PD'erne er fra samme tabel, men jeg skal have dem ud i en enkelt tuple

Takker!
Avatar billede erikjacobsen Ekspert
06. juli 2006 - 15:31 #1
Hvorfor er PD4, PD7, PD6 osv ikke een tabel med eet ekstra felt, der siger om det er 4, 6, 7 osv ?
Avatar billede misbruger Nybegynder
06. juli 2006 - 16:36 #2
Det er det da også....

Min tabeller:

ProductData
- Indeks INT PK
- Product INT FK
- DataType INT FK
- val VARCHAR(200)

ProductDataType
- Indeks INT PK
- [Name] VARCHAR(20) FK

Eks. tupler fra ProductData
1, 15, 4, '700 gram netto'
1, 15, 6, '120 sider manual'

Eks. tupler fra ProductDataType
4, 'Netto vægt'
6, 'Manual'
Avatar billede erikjacobsen Ekspert
06. juli 2006 - 17:06 #3
Ja, det er varmen :)  Jeg skulle måske tage og læse det du faktisk skriver.

Skal det komme ud som 9 værdier på "langs", eller kan du nøjes med:

SELECT P.indeks, PD.val
FROM Products P LEFT JOIN ProductData PD ON P.indeks = PD.product and PD.dataType IN (4,7,6,10,16,1,5,3,2)
Avatar billede misbruger Nybegynder
06. juli 2006 - 21:36 #4
Nej det skal selvfølgelig komme ud "på langs"
En enkelt tuple/record/row :D
Avatar billede arne_v Ekspert
06. juli 2006 - 21:40 #5
saa er der vist ikke mange muligheder

hvis du vil have X vaerdier fra samme kolonne og X forskellige raekker
ud i en raekke i et query output maa der skulle X-1 joins til
Avatar billede misbruger Nybegynder
06. juli 2006 - 22:03 #6
tja det mente jeg nok også, men det kunne være der var en smart funktion der var gået min næse forbi.

btw SQL 2005

Under design og ca 90% inde i implementation, var det en fornuftig opbygning, indtil kunden ligepludselig fik noget galt i halsen, og kom på andre tanker. SÅ nu står jeg ved at stort performance issue pga alle disse joins.

Ellers tak!
Avatar billede arne_v Ekspert
06. juli 2006 - 22:10 #7
er der index paa indeks, product og datatype kolonnerne ?

hvor mange raekker er der i tabellen ?

er det CPU, memory eller disk IO som er flaskehalsen ?
Avatar billede erikjacobsen Ekspert
06. juli 2006 - 22:24 #8
Men så må du forklare hvorfor det skal være på "langs". En SQL-forespørgsel skal give dig de data du har brug for, mens præsentationen for brugeren klares andetsteds. Hvis du får data ud sådan ca. som skitseret kan du vil programmere dig til at vise det på "langs"
Avatar billede misbruger Nybegynder
06. juli 2006 - 22:46 #9
der er index på både product og datatype.

der er ca. 3,5 mill poster i products (vokser med ca. 20K om månedet)
der er ca 13,5 mill poster i tabellen (vokser med ca. 90K om månedet)
desuden laves der allerede en temlig kompliceret prisberegning pr. produkt, som ligger i en adskilt funktion, der joines med det enkelte produkt. (se nedenstående)

der kommer til at være et throughput på ca. 25-40 forspørsler på 1-10 produkter i sek.

pt. er det processor og IO der giver balladen.

i morgen bliver der smidt en extra proc. i (nr.2/2), og en extra GB ram (bliver til 3 GB) men serveren allerede max'et ud med et RAID1 til OS og et RAID5 med 4 diske til data, som desværre holder både data og logs (Temp database ligger dog på RAID1)

Gode forslag er velkommende
(dog er der ikke økonomi til megen udvidelse)

......
Men måske du har et godt forslag til denne...

SELECT P.indeks, P.title, P.article, PP.Price, PP.Discount, PP.shippingFee, PP.savings, PP.PriceIndeks
FROM Products P
  INNER JOIN V_ProductDataView PDV ON P.indeks = PDV.ProductIndeks
  INNER JOIN dbo.fn_GetProductPrice(P.indeks, @Currency, @Purchaser) PP ON P.indeks = PP.ProductIndeks

Hvor dbo.fn_GetProductPrice() er en inline table function, der returnere 5 kolonner som alle skal bruges i hvert enkelte row af slut produktet.

Problemet med ovenstående er at man ikke kan bruge P.indeks som parameter til funktionen da det vil give følgende fejl "The multi-part identifier "P.indeks" could not be bound." (Ved godt det ikke kan lade sig gøre)

Jeg har også prøvet...

SELECT P.indeks, P.title, P.article, dbo.fn_GetProductPrice(P.indeks, @Currency, @Purchaser)
FROM Products P
  INNER JOIN V_ProductDataView PDV ON P.indeks = PDV.ProductIndeks

Men man kan jo kun kalde en function der returnere scalar værdier som kolonne i en select statement

Måske du kender en funktion der tilføje alle kolonnerne fra en table function til min select statement ?

PT. brugere jeg en Cursor til hente 10 fully loaded produkter, og den kan også mærkes på performance (sidder pt dybt begravet i mine execution plans)
Avatar billede misbruger Nybegynder
06. juli 2006 - 23:04 #10
ericjacobsen ->
Hvis jeg skal bruge 10 produkter, som alle bliver multipliceret ud på 9 rækker (tilsvarende antallet af datatypes), vil jeg skulle returnerer et recordsæt på 90 poster, som efterfølgende skal sendes over webservices, til en ekstern klient.

Oprindeligt var det tilsigtede at klienten skulle hente 10 produkter, og for hvert produkt hente en collection af ProductData. Dette er desværre blevet udelukket, og det er blevet et krav at hente alle værdier på en enkelt Product record.

Pt. er dette blevet pålagt databasen, men det kan selvfølgelig være det skal ligges over i mit Data Access Layer (C#) i steden for, ved at iterere over et dataset, og fylde min DTO's property gennem reflections
Under alle omstændigheder er det udelukket at det skal håndteret på klienten.

Men det er jo også derfor jeg spørger herinde... Så jeg kan få tilsagn fra andre kloge hoveder.
Avatar billede erikjacobsen Ekspert
07. juli 2006 - 08:50 #11
90 poster i sig selv er vel ikke noget problem. Uden at kunne gå i detaljer med din problemstilling skal du vel finde den billigste kombination af sql-kald + DAL-kode + klientkode (hvis der må ændres noget der). Så er det bare et gå i gang ;)
Avatar billede ldanielsen Nybegynder
07. juli 2006 - 12:46 #12
Rent bortset fra alle jeres betragtninger kunne en User Defined Function løse problemet.

Den skal jo så kaldes 9 gange, men det bliver pænt at se på ...
Avatar billede misbruger Nybegynder
07. juli 2006 - 15:45 #13
erik -> Det tror du har ret. Er nu gået i gang med at ligge kald til ProductData over i mit DAL.

ldanielsen -> Nu er problemet jo ikke lige frem om det er pænt eller ej. Performance er mit issue, og dit forslag om at kalde en scalar function 9 gang i min select statement vil være en væsentlig forringelse.

Tak!
Avatar billede misbruger Nybegynder
07. juli 2006 - 23:50 #14
Ok. fandt ud af at det største problem faktisk lå i, at den ikke havde oprettet index på mit view. (Kan den jo ikke når man brugere outer joints)

Så nu har jeg lagt et ekstra kald pr. produkt ud i min DAL, som henter alle ProductData, og iterere igennem dem med en simpel switch-case på DataType.

Performance er igen med på beatet.

eric-> Smid venligst et svar
Avatar billede erikjacobsen Ekspert
08. juli 2006 - 00:02 #15
Jeg samler slet ikke på point, tak. Det lyder som en rigtig (rigtigere...) løsning.
Avatar billede misbruger Nybegynder
04. september 2006 - 21:01 #16
Ok!
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Computerworld tilbyder specialiserede kurser i database-management

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester