20. april 2005 - 14:55Der er
29 kommentarer og 1 løsning
query optimering
Jeg har denne query... Jeg syntes nu at det er noget langsom... Er der nogle der har nogle ideer til optimering.?
--- select top 10 tbl_profil.str_id as str_id,tbl_billeder.str_id as tbl_billeder_str_id,str_ext,str_køn from tbl_profil join tbl_profil_besøg on tbl_profil.str_id = tbl_profil_besøg.str_profil_id join tbl_billeder on tbl_profil.str_id = tbl_billeder.str_profil_id where tbl_profil.str_sidstelogin > (dateadd(mm,-1,getdate())) and tbl_profil.str_sidstelogin < getdate() and tbl_profil_besøg.str_dato < (dateadd(mm,-1,getdate())) and str_køn = 1 group by tbl_profil.str_id, tbl_billeder.str_id,str_ext,str_køn ORDER BY NEWID() ---
Mød en af Nordens fremmeste eksperter i adfærdsdesign – Morten Münster, der bl.a. har skrevet ” Jytte fra marketing er desværre gået for i dag” – på Computerworld Cloud & AI Festival.
er det her hurtigere? har jo ikke lige noget testdata at lege med.
select top 10 tp.str_id as str_id, tb.str_id as tbl_billeder_str_id, str_ext, 1 from tbl_profil tp inner join tbl_profil_besøg tpb on tp.str_id = tpb.str_profil_id inner join tbl_billeder tb on tp.str_id = tb.str_profil_id where tp.str_sidstelogin > (dateadd(mm,-1,getdate())) and tp.str_sidstelogin < getdate() and tpb.str_dato < (dateadd(mm,-1,getdate())) and str_køn = 1 ORDER BY NEWID()
hvis det er nødvendigt kan du jo putte din group by clause på igen. ********** select top 10 tp.str_id as str_id, tb.str_id as tbl_billeder_str_id, str_ext, str_køn from tbl_profil tp inner join tbl_profil_besøg tpb on tp.str_id = tpb.str_profil_id inner join tbl_billeder tb on tp.str_id = tb.str_profil_id where tp.str_sidstelogin > (dateadd(mm,-1,getdate())) and tp.str_sidstelogin < getdate() and tpb.str_dato < (dateadd(mm,-1,getdate())) and str_køn = 1 group by tp.str_id, tb.str_id,str_ext,str_køn ORDER BY NEWID() ********* en anden ting er at du rent faktisk vælger at pille str_køn ud af din query, men i din where clause skriver du explicit at den skal være 1, så du kunne i din select skrive select bla,bla,bla,1 from ....
hvis det er nødvendigt kan du jo putte din group by clause på igen. ********** select top 10 tp.str_id as str_id, tb.str_id as tbl_billeder_str_id, str_ext, str_køn from tbl_profil tp inner join tbl_profil_besøg tpb on tp.str_id = tpb.str_profil_id inner join tbl_billeder tb on tp.str_id = tb.str_profil_id where tp.str_sidstelogin > (dateadd(mm,-1,getdate())) and tp.str_sidstelogin < getdate() and tpb.str_dato < (dateadd(mm,-1,getdate())) and str_køn = 1 group by tp.str_id, tb.str_id,str_ext,str_køn ORDER BY NEWID() ********* en anden ting er at du rent faktisk vælger at pille str_køn ud af din query, men i din where clause skriver du explicit at den skal være 1, så du kunne i din select skrive select bla,bla,bla,1 from ....
Men jeg syntes stadigvæk at den er langsom... Nogle tips?
--- select top 10 tp.str_id as str_id, tb.str_id as tbl_billeder_str_id, str_ext, 1 from tbl_profil tp inner join tbl_profil_besøg tpb on tp.str_id = tpb.str_profil_id inner join tbl_billeder tb on tp.str_id = tb.str_profil_id where tp.str_sidstelogin > (dateadd(mm,-1,getdate())) and tp.str_sidstelogin < getdate() and tpb.str_dato < (dateadd(mm,-1,getdate())) and str_køn = 0 group by tp.str_id ,tb.str_id, str_ext ORDER BY NEWID() ---
prøv med følgende. du skal have db med som står sidt i sætningen.
******* select top 10 * from (select DISTINCT tp.str_id as str_id, tb.str_id as tbl_billeder_str_id, str_ext, 1 from tbl_profil tp inner join tbl_profil_besøg tpb on tp.str_id = tpb.str_profil_id inner join tbl_billeder tb on tp.str_id = tb.str_profil_id where tp.str_sidstelogin > (dateadd(mm,-1,getdate())) and tp.str_sidstelogin < getdate() and tpb.str_dato < (dateadd(mm,-1,getdate())) and str_køn = 0
db er synonym for min subquery, og skal være på for at man kan lave en sådan. Hvis du har et script til at lave tabellerne, og til at fylde nogle testdata i, vil jeg gerne sidde og lege lidt med det, men det kræver nok jeg har nogle faktiske data at pille ved, så jeg kan se hvor jeg kan optimere, og om det er muligt ast lave en række queries, som så kan lægges sammen.
jeg sidder lige og bikser med noget, hvis du går ind på din SQL server i enterprize manager, og vælger den rigtige database, og herefter diagram. Herefter højreklikker du på den blanke flade og vælger nyt diagram. Så ltager du de tabeller som har relation til dette query, og vupti så har di et diagram over tabellerne. herefter markerer du alle tabellerne, højreklikker på en af tabellernes top bar, og vælger all tasks | generate sql script.
herefter kan du så få lavet et script som opretter tabellerne, som jeg så kan kigge på. dog uden data, men det væsentligste er også at jeg kan se om jeg kan få optimeret søgningen.
--- if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[tbl_betalt_profilbesøg]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table [dbo].[tbl_betalt_profilbesøg] GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[tbl_billeder]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table [dbo].[tbl_billeder] GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[tbl_profil]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table [dbo].[tbl_profil] GO
CREATE TABLE [dbo].[tbl_betalt_profilbesøg] ( [uniqueid] [int] IDENTITY (1, 1) NOT FOR REPLICATION NOT NULL , [str_måned] [int] NULL , [str_år] [int] NULL , [str_profil_id] [uniqueidentifier] NULL , [str_dato] [datetime] NULL ) ON [PRIMARY] GO
klart... --- if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[tbl_betalt_profilbesøg]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table [dbo].[tbl_betalt_profilbesøg] GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[tbl_billeder]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table [dbo].[tbl_billeder] GO
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[tbl_profil]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table [dbo].[tbl_profil] GO
CREATE TABLE [dbo].[tbl_betalt_profilbesøg] ( [uniqueid] [int] IDENTITY (1, 1) NOT FOR REPLICATION NOT NULL , [str_måned] [int] NULL , [str_år] [int] NULL , [str_profil_id] [uniqueidentifier] NULL , [str_dato] [datetime] NULL ) ON [PRIMARY] GO
næh, du har jo ingen relationer imellem tabellerne med fremmednøgler, er det med vilje? Du bør nok lave fremmednølerne, som sikrer dig imod inkonsistente data, og dermed indirekte måske kan afhjælpe noget af dit hastighedsproblem.
hvad er forskellen på uniqueid og str_id i profil-tabellen? Det ser ud til der er en del normalisering at gør på tabellerne i forhold til de query du fyrede afsted til at starte med.
ok. jeg ser grundlæggende et problem i at du har en str_id, som kn være null, og som refererer til en anden tabel. prøv at lave en
select * from tbl_profil where str_id is null
normalt så joiner man tabeller sammen på deres primærnøgle. du er igang med at joine sammen på en anden kolonne. det betyder i praksis, at du kan have den samme str_id for flere forskellige profiler, da de ikke er unikke(selvom du bruger newid til at allokere dem med, kan man potentielt få ændre den til at være det samme som i en anden profil). Ved at lave relationer imellem tabeller med fremmednøgler, så sikre du at hvis du sletter en profil, vil den brokke sig over at det ligger data i andre tabeller, som refererer til denne profil. på den måde kan man rydde op i data, dermed mindske datamængden, og dermed øge performance.
læs evt. lidt om normaliser af databaser til 3NF(tredje normal form). Grundlæggende bør data kun være afhngigt af primærnøglen, hvis andet er tilfældet bør den data splittes op i en tabel. Relationer imellem tabeller opretholdes med fremmednøgle i den nye tabel, som relaterer til primærnøglen i den oprindelige tabel.
håber det afklarede et par ting, ellers skriv igen.
Herman har ret, det handler næsten sikkert om indexer.
ALLE tabeller skal have en primær nøgle, og det har dine ikke. Når du laver en primær nøgle oprettes der samtidig et index på kolonnen. Desuden skal du enten lave indexer for de kolonner du vil joine på, eller lave fremmednøgler. Og sidst kan de være en god ide at lave indexer på de kolonner du bruger i WHERE, ORDER BY og GROUP BY.
Jeg har selv oplevet at en query blev kørt på 5% af den oprindelige tid, bare fordi jeg lavede et par indexer.
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.