Avatar billede chrede Nybegynder
14. juli 2004 - 01:09 Der er 30 kommentarer og
2 løsninger

Billeder i MySql database

Jeg er ved at lave et online billede galleri, og jeg overvejer i den forbindelse at lægge billederne i en MySql database.

Er det dumt? skal jeg hellere ligge links (filnavne) i DB'en istedet, og så beholde billederne på disken?

og hvorfor det ene, fremfor det andet?
Avatar billede chrede Nybegynder
14. juli 2004 - 01:10 #1
galleriet er for resten lavet i asp.net
Avatar billede taskmgr Nybegynder
14. juli 2004 - 01:45 #2
Efter min egen personlige erfaring, er fordelen at det er nemmere at vedligeholde f.eks. et galleri i MySQL, fordi du kun skal bekymre dig om hvad der ligger dér og ikke rode med filsystemet. Det er derfor også nemmere at lave backup/restore.

Ulempen må være dårligere performance (har dog aldrig testet)
Avatar billede arne_v Ekspert
14. juli 2004 - 08:15 #3
Der er mange som er forfærdeligt bange for at ligge billeder
ind i databaser p.g.a. performance.

Jeg tror at altså at meget af det skyldes sårlige erfaringer med MS Access
fra engang midt i 90'erne.

MySQL på noget fornuftigt hardware bør sagtens kunne klare billeder.

Og som taskmgr siger så er det langgt nemmere at styre, når de er i selve
databasen.
Avatar billede chrede Nybegynder
14. juli 2004 - 11:04 #4
okay... Men er performance den eneste ulempe ved at putte dem i MySql?
Avatar billede arne_v Ekspert
14. juli 2004 - 11:06 #5
Ja.

Så vidt jeg ved.
Avatar billede michael_stim Ekspert
14. juli 2004 - 11:06 #6
Et galleri ville jeg absolut ikke lägge i en MySQL-database. Efter min erfaring kan den ikke klare det.
//Michael
Avatar billede chrede Nybegynder
14. juli 2004 - 11:07 #7
michael_stim -> Okay, du har altså bøvlet med det? eller hvad ?
Avatar billede michael_stim Ekspert
14. juli 2004 - 11:09 #8
Ja, og jeg fortryder at jeg lagde dem i databasen, gör det aldrig igen.
Er det et enkelt billede eller lignende der skal kaldes på så OK, men ikke et helt galleri.
Avatar billede chrede Nybegynder
14. juli 2004 - 11:12 #9
michael_stim -> men det er altså performance der halter?
Avatar billede michael_stim Ekspert
14. juli 2004 - 11:12 #10
ja
Avatar billede chrede Nybegynder
14. juli 2004 - 11:15 #11
Ok, jeg lader lige sprgm. så åben lidt endnu... vil lige se om der kommer inputs fra andre :-)
Men alle der har deltaget og som er interesseret i points skal bare smide et svar
Avatar billede arne_v Ekspert
14. juli 2004 - 12:10 #12
svar
Avatar billede taskmgr Nybegynder
14. juli 2004 - 12:12 #13
Svar.

michael_stim, har du evt. nogle testresultater?
Avatar billede chrede Nybegynder
14. juli 2004 - 12:16 #14
ja det kunne være cool og se :-)
Avatar billede michael_stim Ekspert
14. juli 2004 - 12:18 #15
No points for me ;o)
taskmgr>>Desvärre ingen dokumenterede resultater, kun mine egne erfaringer.
Avatar billede Slettet bruger
14. juli 2004 - 12:19 #16
En anden relevant ting er, at hver tabel i MySQL er en fil, og derfor er underlagt de begrænsninger for filstørrelser, som operativsystemet sætter. Alt efter hvilket operativsystem kan grænsen være på 2 GB, 4 GB eller ikke-eksisterende (med nutidige harddiske).
Avatar billede arne_v Ekspert
14. juli 2004 - 17:52 #17
Jeg har lige lavet en lille test.

Et C# program som henter tilfældigt udvalgte billeder af en MySQL database.

ca. 30 billeder per sekund kunne det hente

Og disken er en 5 år gammel 17 GB ATA-66 5400 RPM 2 MB, så der er al mulig grund
til at tro at en ny disk vil performe betydeligt bedre.
Avatar billede chrede Nybegynder
14. juli 2004 - 17:56 #18
vil du låne din test kode ud? for så vil jeg prøve det af på mit webhotel (www.web10.dk) får at se hvordan det performer på deres DB server/netværk
Avatar billede arne_v Ekspert
14. juli 2004 - 17:58 #19
using System;
using System.Threading;
using System.Data;
using ByteFX.Data.MySqlClient;

public class PicTestThread
{
    private int n;
    private int npics;
    private int picsize;
    public PicTestThread(int n, int npics, int picsize)
    {
        this.n = n;
        this.npics = npics;
        this.picsize = picsize;
    }
    public void Run()
    {
        PicTest.CheckN(n, npics, picsize);
    }
}

public class PicTest
{
    private const int N = 10000;
    public static void CreateTable(int npics, int picsize)
    {
        MySqlConnection con = new MySqlConnection("Database=Test;Data Source=localhost;User Id=;Password=");
        con.Open();
        MySqlCommand cre = new MySqlCommand("CREATE TABLE pics (id INTEGER PRIMARY KEY, pic MEDIUMBLOB)", con);
        cre.ExecuteNonQuery();
        MySqlCommand ins = new MySqlCommand("INSERT INTO pics VALUES (@id, @pic)", con);
        ins.Parameters.Add("@id", MySqlDbType.Int);
        ins.Parameters.Add("@pic", MySqlDbType.MediumBlob);
        for(int i = 0; i < npics; i++)
        {
            ins.Parameters["@id"].Value = i;
            byte[] data = new Byte[picsize];
            for(int j = 0; j < picsize; j++)
            {
                data[j] = (byte)((i + j) % 256);
            }
            ins.Parameters["@pic"].Value = data;
            ins.ExecuteNonQuery();
        }
        con.Close();
    }
    public static void CheckOne(int id, int picsize)
    {
        MySqlConnection con = new MySqlConnection("Database=Test;Data Source=localhost;User Id=;Password=");
        con.Open();
        MySqlCommand sel = new MySqlCommand("SELECT pic FROM pics WHERE id = " + id, con);
        byte[] data = (byte[])sel.ExecuteScalar();
        if(data.Length != picsize)
        {
            Console.WriteLine("picture #" + id + " corrupted");
        }
        for(int j = 0; j < data.Length; j++)
        {
            if(((id + j) % 256) != data[j])
            {
                Console.WriteLine("picture #" + id + " corrupted");
            }
        }
        con.Close();
    }
    public static void DropTable()
    {
        MySqlConnection con = new MySqlConnection("Database=Test;Data Source=localhost;User Id=;Password=");
        con.Open();
        MySqlCommand drp = new MySqlCommand("DROP TABLE pics", con);
        drp.ExecuteNonQuery();
        con.Close();
    }
    public static void CheckN(int n, int npics, int picsize)
    {
        Random rng = new Random();
        for(int i = 0; i < n; i++)
        {
            int id = rng.Next(npics);
            CheckOne(id, picsize);
        }
    }
    public static void CheckTest(int nthreads, int npics, int picsize)
    {
        long t1 = DateTime.Now.Ticks;
        PicTestThread[] ptt = new PicTestThread[nthreads];
        Thread[] thr = new Thread[nthreads];
        for(int i = 0; i < thr.Length; i++)
        {
            ptt[i] = new PicTestThread(N/nthreads, npics, picsize);
            thr[i] = new Thread(new ThreadStart(ptt[i].Run));
        }
        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(nthreads + " conc reqs, " +
                          npics + " pics in db, " +
                          picsize/1000 + " KB pics => " +
                          N/((t2 - t1) / 1000000.0) + " pics/sec");
    }
    public static void Main(string[] args)
    {
        int[] npics = { 250, 500, 1000 };
        int[] picsize = { 50000 /*, 100000, 200000 */ };
        int[] nthreads = { 10, 20, 40 };
        for(int i = 0; i < npics.Length; i++)
        {
            for(int j = 0; j < picsize.Length; j++)
            {
                CreateTable(npics[i], picsize[j]);
                for(int k = 0; k < nthreads.Length; k++)
                {
                    CheckTest(nthreads[k], npics[i], picsize[j]);
                }
                DropTable();
            }
        }
    }
}
Avatar billede arne_v Ekspert
14. juli 2004 - 17:59 #20
Det er en C# console app ikke en ASP.NET/C# side.

Men du må kunne genbruge meget af koden.

Jeg bruger ByteFX driver.

Grunden til at jeg kun tester 50KB pics er at der er en stor led bug
i ByteFX for >64K felter.

Den er lovet fixet i denne uge ...
Avatar billede chrede Nybegynder
14. juli 2004 - 18:00 #21
ok
Avatar billede chrede Nybegynder
14. juli 2004 - 18:23 #22
Kan man ekportere data og tabel i mysql når man har billeder i... for så kunne jeg slippe for at oprette dem, jeg er nemlig ikke # til C# endnu...  :o)
Avatar billede arne_v Ekspert
14. juli 2004 - 18:35 #23
Det vil jeg da tro, selvom jeg aldrig har prøvet.
Avatar billede chrede Nybegynder
14. juli 2004 - 19:27 #24
Det lykkedes ikke at lave det om... men jeg prøver det nok en anden gang..

Men tak for jeres inputs :-)
Avatar billede avminarm Juniormester
16. juli 2004 - 13:04 #25
chrede>> jeg har selv bakset med billeder i databasen (via PHP) og jeg syntes nu ikke der var mærkbar performence ændring i forhold til når filerne ligger i en mappe - det der er afgørende for performencen - tror jeg - er størrelsen på dine billeder - ikke om det er en DB eller en mappe.
Avatar billede arne_v Ekspert
16. juli 2004 - 13:11 #26
Der er nu nok forskel men ofte er det netvæærket der er flaskehals.

Min test gav 30 x 50 KB / sekund = 1500 KB / sekund.

Det kræver altså en 12+ Mbit forbindelse.

(og som sagt er disken antik)
Avatar billede chrede Nybegynder
16. juli 2004 - 14:17 #27
hvis nogen ligger inde med en test som den Arne_v har lavet, bare til web, vil jeg gerne høre om det..

tak for jeres inputs.
Avatar billede arne_v Ekspert
16. juli 2004 - 22:52 #28
Nå jeg lavede det lige om fra en C# app til en ASP.NET/C# side.

pictest.aspx:

<%@ Page Language="C#" %>
<%@ Import Namespace="E8" %>
<%
        int[] npics = { 250, 500, 1000 };
        int[] picsize = { 50000 /*, 100000, 200000 */ };
        int[] nthreads = { 10, 20, 40 };
        for(int i = 0; i < npics.Length; i++)
        {
            for(int j = 0; j < picsize.Length; j++)
            {
                PicTest.CreateTable(npics[i], picsize[j]);
                for(int k = 0; k < nthreads.Length; k++)
                {
                    Response.Write(PicTest.CheckTest(nthreads[k], npics[i], picsize[j]) + "<br/>");
                }
                PicTest.DropTable();
            }
        }
%>

pictest.cs:

using System;
using System.Threading;
using System.Data;
using ByteFX.Data.MySqlClient;

namespace E8
{
    public class PicTestThread
    {
        private int n;
        private int npics;
        private int picsize;
        public PicTestThread(int n, int npics, int picsize)
        {
            this.n = n;
            this.npics = npics;
            this.picsize = picsize;
        }
        public void Run()
        {
            PicTest.CheckN(n, npics, picsize);
        }
    }
   
    public class PicTest
    {
        private const int N = 10000;
        public static void CreateTable(int npics, int picsize)
        {
            MySqlConnection con = new MySqlConnection("Database=Test;Data Source=localhost;User Id=;Password=");
            con.Open();
            MySqlCommand cre = new MySqlCommand("CREATE TABLE pics (id INTEGER PRIMARY KEY, pic MEDIUMBLOB)", con);
            cre.ExecuteNonQuery();
            MySqlCommand ins = new MySqlCommand("INSERT INTO pics VALUES (@id, @pic)", con);
            ins.Parameters.Add("@id", MySqlDbType.Int);
            ins.Parameters.Add("@pic", MySqlDbType.MediumBlob);
            for(int i = 0; i < npics; i++)
            {
                ins.Parameters["@id"].Value = i;
                byte[] data = new Byte[picsize];
                for(int j = 0; j < picsize; j++)
                {
                    data[j] = (byte)((i + j) % 256);
                }
                ins.Parameters["@pic"].Value = data;
                ins.ExecuteNonQuery();
            }
            con.Close();
        }
        public static void CheckOne(int id, int picsize)
        {
            MySqlConnection con = new MySqlConnection("Database=Test;Data Source=localhost;User Id=;Password=");
            con.Open();
            MySqlCommand sel = new MySqlCommand("SELECT pic FROM pics WHERE id = " + id, con);
            byte[] data = (byte[])sel.ExecuteScalar();
            if(data.Length != picsize)
            {
                Console.WriteLine("picture #" + id + " corrupted");
            }
            for(int j = 0; j < data.Length; j++)
            {
                if(((id + j) % 256) != data[j])
                {
                    Console.WriteLine("picture #" + id + " corrupted");
                }
            }
            con.Close();
        }
        public static void DropTable()
        {
            MySqlConnection con = new MySqlConnection("Database=Test;Data Source=localhost;User Id=;Password=");
            con.Open();
            MySqlCommand drp = new MySqlCommand("DROP TABLE pics", con);
            drp.ExecuteNonQuery();
            con.Close();
        }
        public static void CheckN(int n, int npics, int picsize)
        {
            Random rng = new Random();
            for(int i = 0; i < n; i++)
            {
                int id = rng.Next(npics);
                CheckOne(id, picsize);
            }
        }
        public static string CheckTest(int nthreads, int npics, int picsize)
        {
            long t1 = DateTime.Now.Ticks;
            PicTestThread[] ptt = new PicTestThread[nthreads];
            Thread[] thr = new Thread[nthreads];
            for(int i = 0; i < thr.Length; i++)
            {
                ptt[i] = new PicTestThread(N/nthreads, npics, picsize);
                thr[i] = new Thread(new ThreadStart(ptt[i].Run));
            }
            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;
            return (nthreads + " conc reqs, " +
                    npics + " pics in db, " +
                    picsize/1000 + " KB pics => " +
                    N/((t2 - t1) / 1000000.0) + " pics/sec");
        }
    }
}
Avatar billede chrede Nybegynder
19. juli 2004 - 22:59 #29
takker :-)
Avatar billede chrede Nybegynder
20. juli 2004 - 12:29 #30
10pics / sek.... for lidt hos web10 synes jeg :-(
(1 tråd, size=50000, pics# = 50)
Avatar billede arne_v Ekspert
20. juli 2004 - 13:02 #31
500 KB/sek = 4 Mbit

Umiddelbart er jeg skeptisk overfor om du kan få mere båndbredde !
Avatar billede chrede Nybegynder
20. juli 2004 - 13:12 #32
Ja.
Jeg holder mig til filer, indtil jeg får min egen web/db server op og køre...
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