04. november 2005 - 03:21Der er
18 kommentarer og 2 løsninger
Hastighed i forhold til grafik elementer fra databse
Hejsa
Jeg har tænkt på hvis man gemmer binær data(grafik i mit tilfælde) i en database. Hvordan er hastigheden så i forhold til hvis man henter det direkte fra en mappe. Og hvordan påvirker det serverens performence ?
I mange år har det været god latin at performance er meget bedre ved at gemme filnavne i databasen og selve filerne ved siden af fremfor at gemme indholdet i databasen.
Men der sker fremskridt hele tiden. Og jeg tror ikke på at rådet er validt længere.
Med moderne software og moderne hardware bør du kunne gemme filerne i databasen.
Et argument for mit synspunkt er at både Oracle og Microsoft enten har eller er ved at udvikle fil system som bruger databasen til storage.
Og det er jo langt nemmere administrationsmæssigt.
Synes godt om
Slettet bruger
05. november 2005 - 05:57#2
Arne har måske ret hvis og kun hvis performance defineres, som sitet svarer acceptabelt. Hvis det du spørger om er om det er hurtigere at serve billeder direkte fra disk eller serve dem fra en database, så er der vist ingen tvivl om hvad der er hurtigst. Hvis du har billederne i en database så skal du transportere den BLOB , som representere billeder, fra databaseserver til en webserver og du skal med en dynamisk side sende billedet til klienten på et request. Det betyder at du bruger noget båndbrede på dit interne netværk (DB-server til webserver) og lige meget hvordan man vender og drejer det så koster det noget. Hvis du har billederne liggende direkte på disk skal din webserver blot håndterer et statisk request og det vil også være hurtigere end et dynamisk request. Ligeledes hvis du lader web-server håndterer billederne, som statisk request er du fri for selv at skulle holde styr på hvilken type (PNG/GIF/JPEG osv...) dine billeder er, hvor hvis du skal sende dem dynamisk skal du selv sende korrekt header information i forbindelse med request.
Der er som jeg ser det kun et argument for at holde billeder i databaser og det er administration. Specielt hvis du skal sælge et CMS eller ligende til kunder, som ikke har den store ekspertise inhouse så kan du have det hele gemt pænt væk i en database.
Men bottom-line hvis du snakker hvad er hurtigst så er det at serve statiske billeder og hvis du har en meget stort site, som tager meget trafik så lav en server kun med statisk indhold.
Der er et par faktorer som også skal tages med: - det koster meget at åbne filer - databaser må formodes at være bedre til at cache da de ved mere om hvordan data hænger sammen
Og vi skal også være opmærksom på hvad vi sammenligner - der er faktisk 12 kombinationer:
billede som fil / billede som fil & billedinfo i db / billede & billedinfo i db lokal db / remote db lokal fil / remote fil
(ja vel reelt kun 10)
Der er formentlig ikke noget som er hurtigere end den rent statiske løsning: billed som fil + lokal fil
Men du sammenligner så: billede som fil & billed info i db + lokal fil + remote db med: billede & billedinfo i db + remote db
Mit gæt vil være at det faktisk afhænger af billedets størrelse. Ved tilpas små billeder kan det sidste faktisk godt være hurtigst. Ved store billeder er det første nok hurtigst.
Men en mere fair sammenligning ville vel også være: billede som fil & billed info i db + remote fil + remote db med: billede & billedinfo i db + remote db eller: billede som fil & billed info i db + lokal fil + lokal db med: billede & billedinfo i db + lokal db
Og der tror jeg altså sagtens at databasen kan være med (ikke mindst i den første sammenligning !).
Synes godt om
Slettet bruger
05. november 2005 - 12:18#4
Uanset hvordan man ser på det så skal en BLOB fra en DB pakkes i DB's protokol og sendes til noget dynamisk, som sender siden - du koster uanset hvordan det er sat sammen. At sende en statisk fil fra en web-server vil være hurtigere og anvende mindre ressourcer. Ligeledes vil almindelig fil-caching i OS håndterer caching af statiske billeder ligeså godt som en DB-cache.
Vær opmærksom på at jeg ikke taler om, om det performer til praktisk brug, jeg taler alene om hvad der er hurtigst, anvender mindst ressourcer og det er og bliver statiske filer.
1000 billeder af 25 KB WinXP & MSDE 2000 i default config lokal db & lokal dir app i C# scenarie 1: række i db med sti (VARCHAR) og ekstern fil scenarie 2: række i db med billede (IMAGE) hente et random billede af gangen
resultat:
Database and file (1 threads): 85 get per second Database and file (10 threads): 175 get per second Only database (1 threads): 250 get per second Only database (10 threads): 242 get per second
Det er markant hurtigere at gemme billedet i databasen.
Nu skal man være lidt forsigtig med hvad man kan konkludere. Man kan ikke konkludere at det altid er hurtigst at gemme billeder i databasen. Jeg er 112% sikker på at jeg sagtens kunne konstruere et eksempel som modbeviste det. Men man må kunne konkludere at det ikke altid er hurtigst at have filer ved siden af databasen.
Og jeg synes ikke at min konfig er så usædvanelig.
Koden for de nysgerrige:
using System; using System.Data; using System.Data.SqlClient; using System.IO; using System.Threading;
namespace E { public class TestClass { private const int NPIC = 1000; private const int PICSIZ = 25000; private const int NGET = 100000; private const string CONNSTR = "Server=ARNEPC3;Integrated Security=SSPI;Database=Test"; private const string BASEDIR = @"C:\pictest\"; private static Random rng; private static int getprthread; public static void SetupDbAndFile() { SqlConnection con = new SqlConnection(CONNSTR); con.Open(); SqlCommand cre = new SqlCommand("CREATE TABLE daf (id INTEGER PRIMARY KEY, path VARCHAR(255))", con); cre.ExecuteNonQuery(); SqlCommand ins = new SqlCommand("INSERT INTO daf VALUES (@id, @path)", con); ins.Parameters.Add("@id", SqlDbType.Int); ins.Parameters.Add("@path", SqlDbType.VarChar); for(int i = 0; i < NPIC; i++) { byte[] b = new byte[PICSIZ]; for(int j = 0; j < b.Length; j++) b[j] = (byte)(i % 256); string fnm = BASEDIR + i + ".pic"; ins.Parameters["@id"].Value = i; ins.Parameters["@path"].Value = fnm; ins.ExecuteNonQuery(); Stream stm = new FileStream(fnm, FileMode.CreateNew, FileAccess.Write); stm.Write(b, 0, b.Length); stm.Close(); } con.Close(); } private static void TestDbAndFileThread() { for(int i = 0; i < getprthread; i++) { int id = rng.Next(NPIC); SqlConnection con = new SqlConnection(CONNSTR); con.Open(); SqlCommand sel = new SqlCommand("SELECT path FROM daf WHERE id = " + id, con); string fnm = (string)sel.ExecuteScalar(); con.Close(); Stream stm = new FileStream(fnm, FileMode.Open, FileAccess.Read); byte[] b = new byte[stm.Length]; stm.Read(b, 0, b.Length); stm.Close(); if(b.Length != PICSIZ) { Console.WriteLine("Error"); Environment.Exit(1); } for(int j = 0; j < b.Length; j++) { if(b[j] != (byte)(id % 256)) { Console.WriteLine("Error"); Environment.Exit(1); } } } } public static void TestDbAndFile(int nthreads) { rng = new Random(1234567); getprthread = NGET / nthreads; Thread[] thr = new Thread[nthreads]; for(int i = 0; i < thr.Length; i++) { thr[i] = new Thread(new ThreadStart(TestDbAndFileThread)); } long t1 = DateTime.Now.Ticks; for(int i = 0; i < thr.Length; i++) { thr[i].Start(); } for(int i = 0; i < thr.Length; i++) { thr[i].Join(); } long t2 = DateTime.Now.Ticks; Console.WriteLine("Database and file (" + nthreads + " threads): " + NGET / ((t2 - t1)/1000000) + " get per second"); } public static void DestroyDbAndFile() { SqlConnection con = new SqlConnection(CONNSTR); con.Open(); SqlCommand drp = new SqlCommand("DROP TABLE daf", con); drp.ExecuteNonQuery(); con.Close(); string[] allf = Directory.GetFiles(BASEDIR); foreach(string f in allf) { File.Delete(f); } } public static void SetupOnlyDb() { SqlConnection con = new SqlConnection(CONNSTR); con.Open(); SqlCommand cre = new SqlCommand("CREATE TABLE od (id INTEGER PRIMARY KEY, pic IMAGE)", con); cre.ExecuteNonQuery(); SqlCommand ins = new SqlCommand("INSERT INTO od VALUES (@id, @pic)", con); ins.Parameters.Add("@id", SqlDbType.Int); ins.Parameters.Add("@pic", SqlDbType.Image); for(int i = 0; i < NPIC; i++) { byte[] b = new byte[PICSIZ]; for(int j = 0; j < b.Length; j++) b[j] = (byte)(i % 256); ins.Parameters["@id"].Value = i; ins.Parameters["@pic"].Value = b; ins.ExecuteNonQuery(); } con.Close(); } private static void TestOnlyDbThread() { for(int i = 0; i < getprthread; i++) { int id = rng.Next(NPIC); SqlConnection con = new SqlConnection(CONNSTR); con.Open(); SqlCommand sel = new SqlCommand("SELECT pic FROM od WHERE id = " + id, con); byte[] b = (byte[])sel.ExecuteScalar(); con.Close(); if(b.Length != PICSIZ) { Console.WriteLine("Error"); Environment.Exit(1); } for(int j = 0; j < b.Length; j++) { if(b[j] != (byte)(id % 256)) { Console.WriteLine("Error"); Environment.Exit(1); } } } } public static void TestOnlyDb(int nthreads) { rng = new Random(1234567); getprthread = NGET / nthreads; Thread[] thr = new Thread[nthreads]; for(int i = 0; i < thr.Length; i++) { thr[i] = new Thread(new ThreadStart(TestOnlyDbThread)); } long t1 = DateTime.Now.Ticks; for(int i = 0; i < thr.Length; i++) { thr[i].Start(); } for(int i = 0; i < thr.Length; i++) { thr[i].Join(); } long t2 = DateTime.Now.Ticks; Console.WriteLine("Only database (" + nthreads + " threads): " + NGET / ((t2 - t1)/1000000) + " get per second"); } public static void DestroyOnlyDb() { SqlConnection con = new SqlConnection(CONNSTR); con.Open(); SqlCommand drp = new SqlCommand("DROP TABLE od", con); drp.ExecuteNonQuery(); con.Close(); } public static void Main(string[] args) { SetupDbAndFile(); TestDbAndFile(1); TestDbAndFile(10); DestroyDbAndFile(); SetupOnlyDb(); TestOnlyDb(1); TestOnlyDb(10); DestroyOnlyDb(); } } }
Synes godt om
Slettet bruger
05. november 2005 - 14:52#6
Du streamer jo billedet fra en fil, du skal lade web server sende billedet. Det er der forskellen vil blive betydende. Pointen er jo netop at en web server væsentligt hurtigere kan sende statisk indhold.
Hvis man nu antager at jeg bruger "database til fil" metoden. Så bruger jeg jo også mere diskplads end jeg vil bruge hvis jeg brugte database med billed metoden. For så vidt jeg ved kan man komprimere binær data i en database også. Derved er der måske sparet endnu mere ? altå både tid og pladsforbrug
det er hurtigt at serve filerne direkte af web serveren, men der kan også være nogle sikkerhedsmæssige problemer ved det
og gevindsten er ikke så stor som man kunne tro
jeg copy pastede ovenstående kode over i nogle ASP.NET sider og et lille multi browser simulator program
resultat:
Picture file served by web server (1 threads): 34 get per second Picture file served by web server (10 threads): 43 get per second Picture from database via script (1 threads): 30 get per second Picture from database via script (10 threads): 38 get per second
forskellen er kun knap 10%
og hvis man så lige orker at skrive 5 linier kode så man bruger ASP.NET Cache objekt så ser resultatet ud som:
Picture file served by web server (1 threads): 34 get per second Picture file served by web server (10 threads): 43 get per second Picture from database via script (1 threads): 33 get per second Picture from database via script (10 threads): 44 get per second
ingen forskel !
Med idags databaser og hardware er der i mange tilfælde ingen performance mæssige grunde til ikke at smide billeder i databasen. Og gode administrations mæssige grunde til at gøre det.
har været bange for at min mysql og mssql server vil få min server processor til at "koge" over. Men det lyder ikke til at det forholder sig sådan. Så jeg vil da helt sikkert vælge billede fra database så. Og ja det giver helt sikkert en nemmere mulighed for at styre dem administrativt mæssigt.
i php kan man udregne CPU tiden som er brugt på at IIS serveren har brugt. Kender du en måde man kan udregne det i asp ?
Synes godt om
Slettet bruger
06. november 2005 - 05:50#13
Det forekommer mig der er noget galt... Det simple rationale lyder at mængden af kode, som skal eksekveres ved et dynamisk kald er mange, ja rigtigt mange endda, gange større end ved statisk indhold.
Det der kan ske er selvfølgelig at du drukner netværksforbindelsen inden du ser den reele forskel, ved du hvad den maksimale mængde du kan hælde igennem er? Det er velkendt ved mange sammenligninger mellem eksempelvis IIS og Apache at IIS oftest er hurtigst på statisk indhold, men mod argumentet lyder at man når toppen af sin båndbrede inden det på nogen måder bliver betydende. Er det noget tilsvarende vi ser i din test, at du reelt ikke kan hælde mere igennem?
Grunden til at jeg er så insisterende er at min erfaringer, fra det site (top 5 på FDIM så hr du cirka størrelsen) jeg arbejder for tildaglig har nogle ret konkrete eksempler på at vi skal anvende væsentligt færrer front-end ressourcer ved at anvende statisk indhold frem for dynamisk indhold. Det gælder såvel tekst som billed indhold.
Vil lige minde om at jeg på ingen måder syntes løsningen med at anvende billeder i en DB er gal, der kan være rigtigt mange gode grunde og nogle af dem er allerede nævnt, men rå performance så kan jeg ikke se det og min erfaring siger mig noget helt andet.
du mener netværks båndbredden ? det hele er kørt lokalt og jeg kan ikke tro at 1 MB/s skulle være max der
der er mange faktorer som spiller ind
mit eksempel er med lokal fil og lokal db - hvis det f.eks. er remote db så vil det gøre db langsommere (medmindre man har en usandsynlig god net forbindelse til db server)
større billder ville formentlig også favorisere fil fremfor db
og det ville ikke overraske mig hvis ASP fremfor ASP.NET også ville favorisere fil fremfor db
etc.
jeg tror på at der er mange situationer hvor fil er markant hurtigere end db
det jeg opponerer mod er "alle ved at kun filnavn i db er meget hurtigere end selve filen i db" (uden nogen forudsætninger tilføjet) som er meget almindelig
og det er så ikke møntet på dig, da du jo har nogle konkrete erfaringer
har besluttet mig til og bruge database alligevel...dog hvor den kun henter stien til billedet. Har udvilket et lille billede asp fil...der automatisk henter størrelsen,beskrivelse og alt det andet ind i databasen...så er det lidt nemmere at slette og håndtere filerne...og så selvfølig ved brug af "Filesystem"
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.