Kandidatavhandling i Programvaruteknik 06 2012 Jämförelse av Mysql och MongoDb Alfred Wester Olof Fredriksson Kontaktinformation: Författare: Alfred Wester E-mail: [email protected] Olof Fredriksson E-mail: [email protected] Handledare: Nina D. Fogelström School of Computing Sektionen för datavetenskap och kommunikation Blekinge Tekniska Högskola 371 79 Karlskrona Sweden Internet : www.bth.se/com Phone : +46 455 38 50 00 Fax : +46 455 38 50 57 Abstract. Speed is a very important factor in websites and other types of applications and almost all applications stores some type of data, normally in a database. For an example a blog typically saves users, posts and comments. There’s a high risk that as the amount of data in the database grows, the time for inserting and requesting specific data increases. If it takes more than some seconds to view a specific page, a user will normally leave the site. However, it’s a fact that the database will grow while the application will become more popular but it’s possible to save a lot of time if using right database, and structure. In this thesis MongoDB and MySQL will be compared with focus on time consumption. SQL (Structured Query Language) is the language which most databases use. This kind of database stores data in structured tables and noting can be added to them if the type of data is incorrect. SQL also support relations between tables. MySQL is a very popular relational database management system (RDBMS) which for example websites frequently makes use of. NoSQL is a new type of databases where the data is stored in collections without any kind of structure, unlike the well known SQL databases where the data is stored in structured tables. Because of the non-structure, these types of databases are designed to be fast and scalable over multiple machines. Mongodb is a such kind of NoSql-database. Tests has been done both on inserting and processing when handling up to 4 millions entities, MongoDB performs better in almost every test. Results shows that the processing time is shorter using MongoDb in the cases that this thesis is covering, and that it’s possible to implement a much fast application when using MongoDb instead of Mysql as database. Innehåll 1 2 3 4 5 6 7 8 Introduktion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1 Målgrupp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Bakgrund . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.1 Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 MySql . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3 MongoDb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3.1 Gridfs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.4 Multiinsättning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.5 Json . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.6 PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Forskningsfrågor och metodik . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.1 Frågeställningar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2 Utformining av litteraturstudie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Resultat från litteraturstudie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1 Beskrivning av litteratur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2 Resultat och diskussion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2.1 RQ1. Vilka jämförelser av Sql och NoSql-databaser finns redan och hur utformades de? 4.2.2 RQ2. Vilken databas presterar snabbast när det gäller att sätta in och filtrera data? . . 4.2.3 RQ3. Blir det några skillnader på resultatet vid annan uppsättning av miljö? . . . . . . . . Utformining av experiment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.1 Mål . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 Faktorer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2.1 PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2.2 Operativsystem & Hårdvara . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2.3 Olika datamodeller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2.4 Datamängder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2.5 Vad för typ av data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2.6 Sätta in all data samtidigt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3 Testmiljö . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3.1 Systeminformation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4 Datamodell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Utförande . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.1 Testfall . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2 Insättning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.3 Filtrering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Resultat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.1 Insättning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.1.1 Ubuntu 64 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.1.2 Ubuntu 32 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.2 Filtrering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.2.1 Ubuntu 64 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.2.2 Ubuntu 32 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Analys och diskussion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.1 Tester som inte kunde genomföras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.2 Analys av resultatet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.3 Olika sätt att hantera resultatet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.4 Slutsatser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 5 5 5 5 6 7 7 7 7 8 8 8 8 9 9 10 11 11 12 12 12 12 12 13 13 13 13 13 14 14 14 14 15 16 17 17 17 18 18 18 19 19 19 20 20 20 9 A B C 8.4.1 MongDb är snabbare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.4.2 MongoDb på ett 32-bitars system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.5 Validering av resultat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.6 Kopplingar till tidigare arbeten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.7 Framtida arbete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sammanfattning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Datamodeller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.1 MySql - Insättning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.2 MongoDb - Insättning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.3 MySql - Filtrering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.4 MongoDb - Filtrering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.4.1 Med relationer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A.4.2 Utan relationer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Källkod . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Diagram . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.1 Insättning av data Ubuntu 64 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.2 Insättning av data Ubuntu 32 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.3 Filtrering av data Ubuntu 64 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C.4 Filtrering av data Ubuntu 32 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 21 21 21 21 22 26 26 26 27 28 28 28 29 39 39 39 40 40 1 Introduktion Dagens populära webbtjänster som till exempel Facebook[1] och Twitter[2] sparar undan en stor mängd data kring användarna och de aktiviteter som görs. Samtidigt som det hela tiden växer med information som ska lagras är det fortfarande en hög prioritet att datan ska gå att ladda snabbt, en fördröjning på endast några sekunder kan resultera till i en förlorad användare som i sin tur kan vara förödande för tjänsten. Det finns idag ett flertal olika databastyper där grundprincipen är samma, att skriva och läsa ut data. Det som däremot skiljer dem är deras sätt att hantera datan och hastigheterna att läsa ut från databasen varierar kraftigt. I detta arbete har vi tänkt att testa och jämföra två olika typer av databaser, SQL och NoSql. Vi ska generera ett par tester och mäta vilken av dem som presterar snabbast. Testerna ska, i så stor grad som möjligt, återspegla verkliga scenarion, för att ta reda på hur mycket snabbare MongoDb är istället för MySql och hur strukturen på databasen förändras. Valet av dessa två är dels för att MySql är en av de populäraste databaserna och som många faktiskt känner till. MongoDb är däremot relativt ny och släpptes 2009 så troligtvis är det inte alls lika många som känner till den. I en tidigare uppsats[3] som skrivits jämförs CouchDb och MongoDb där MongoDb vinner i snabbhet på de flesta testerna vilket gör det ännu mer spännande att göra jämförelser med MySql. 1.1 Målgrupp Målgruppen för detta arbete riktar sig till alla som är intresserade eller jobbar med olika typer av databaser. Den grundläggande informationen kring respektive typ finns under sektion 2 bakgrund, men vi rekommenderar ändå att man har några tidigare erfarenheter antingen genom att ha jobbat med databaser eller kan grundprinciperna om hur de fungerar. 2 2.1 Bakgrund Data Data, eller information kan innehålla till exempel uppgifter kring en användare, som namn och lösenord. I vårt fall finns denna information tillgänglig i databaser och hämtas sedan fram med hjälp av anrop. Beroende på hur mycket data man ska hämta hem, och ifall någon filtrering görs så kommer detta ta en viss tid, vilket vi kommer jämföra mellan två de olika typerna. 2.2 MySql Sql är ett språk som hanterar kommunikationen med en relationsdatabas. Språket utvecklades under 70-talet och idag finns det ett flertal databaser som stödjer Sql. MySql[4] är en av dessa och släpptes redan 1995 av MySql AB. Populäriteten ökade snabbt och idag är det ett vanligt alternativ på både hemsidor och andra typer av applikationer. Kortfattat så är en relationsdatabas uppbyggd med tabeller, fält och poster. Anta att det är en tabell med medlemmar, där fälten är namn och lösenord så kommer varje medlem på en separat rad i tabellen. Sql-kommandot för att hämta ut alla medlemmar och dess information görs med en Select[5] som då blir: SELECT * FROM members För att sedan filtrera informationen och bara hämta ut vissa data, används WHERE, LIKE och liknande operationer. Om man nu ska använda tabellen till medlemmar och sedan skapa en enkel form av en blogg, med inlägg och 5 kommentarer kan detta sparas i två separata tabeller. Givetvis är det möjligt att spara användarinformationen i tabellen för inläggen, men då utnyttjar man inte styrkan med relationsdatabaser. Det rekommenderade sättet att strukturera det är att i tabellen för inlägg, endast spara ned id-nummret till användaren, och sedan koppla ihop detta till Member där denna information endast behövs sparas ned på en rad. Samma princip gäller tabellen för kommentarer. Sql-koden för att nu hämta hem alla artiklar som användaren Simba skapat kan nu se ut såhär: SELECT ∗ FROM ` Post ` a s P INNER JOIN Member a s M ON P . idMember = M. idMember AND M. name = ' Simba ' Figur 1: Exempel på en relationsdatabas för medlemmar, blogginlägg och kommentarer I relationsdatabaser används nycklar för att koppla ihop tabellerna. Begreppet kallas för främmande nycklar[6] och kan se till så att datan är konsistent. Ett exampel är att det är möjligt att förhindra att en medlem inte går att radera sålänge det finns artiklar kopplade till användaren, nackdelen är att detta kan leda till att databasen blir slöare för att sätta in och proccessera data. 2.3 MongoDb MongoDb[7] är en slags NoSql-databas som egentligen inte är någon ny teknik, men det är på senare år som det växt otroligt och är idag ett hett ämne när man pratar om stora och skalbara lösningar till sina databaser. Precis som med SQL finns det även flera NoSql-databaser, där de skiljer sig lite från varandra. MongoDb sparar undan informationen i Json-liknande format, BSON. Det är en binär serialisering av Json och är utformat för att vara lättviktigt, enkelt att traversera i samt effektivt[8]. Grunderna kring Json finns i sektion 2.5 Json. Sättet att kommunicera med databasen och hur informationen lagras skiljer sig alltså en hel del i jämförelse med relationsdatabaserna. MongoDb’s motsvarighet till tabeller heter Collections men varje objekt som sätts in kan vara helt olika varandra, det finns inget bestämt vad som ska finnas där. En annan skillnad i jämförelse till MySql är att det även är möjligt att spara ned array’s direkt i objektet. Det kan sparas väldigt mycket tid att ha denna data direkt i objektet än om det funnits i en annan tabell. Däremot kan det behövas mer logik i programmet som hanterar datan, då det inte finns några garantier att datan ser ut på ett visst sätt. 6 Varje objekt som sätts in i databasen kommer få ett unikt id som bland annat baseras på tiden samt process-id[9]. { " _id " : O b j e c t I d ( "4 fd230266803fa9d100003e7 " ) , " title " : " Awesome post " , " content " : " Lorem ipsum dolor sit amet , consectetur adipiscing elit . [...] " , " tags " : { "0" : " dummy post " , "1" : " tag " , "2" : " Mufasa " , } } Listing 1: En relationsfri Collection med inlägg och dess taggar 2.3.1 Gridfs MongoDb har i den senaste versionen (2.0.5) en begränsning på 16MB[10] per objekt och vid insättning av stora filer i databasen kan det därför finnas en risk att filen helt enkelt inte får plats. För att komma runt detta finns GridFs[10] implementerat och skillnaden är att filen automatiskt delas upp i mindre bitar vid behov och begräsningen på en maximal filstorlek försvinner. Det är nu möjligt att spara ned betydligt större filer som till exempel filmer. 2.4 Multiinsättning För både MySql och MongoDb finns ett alternativt sätt att sätta in data: multi-insert för MySql och bulkinsert[11] för MongoDb. Istället för att sätta in ett element i taget, sätts då alla element in med ett enda kommando. Detta är speciellt användbart när många element ska sättas in på samma gång eftersom databasen då endast behöver hantera en request. 2.5 Json JavaScript Object Notation, Json[12] är ett textformat som används till att lagra och skicka data, och har blivit ett alternativ till eXtensible Markup Language, XML. Ett användningsområde där kommunikation med Json används är mellan en server och webbläsare, till exempel om man vill ladda ned innehåll dynamiskt med hjälp av Javascript. { " firstName " : " John " , " lastName " : " Doe " , " phoneNo " : " +4600012 " , " active " : true } Listing 2: Ett exempel på hur ett Json-objekt kan se ut 2.6 PHP PHP[13], som är en rekursiv akronym för PHP Hypertext Preprocessor, är ett populärt programmeringspråk. Användningsområdet är främst inom webbutveckling och används för att till exempel göra beräkningar eller hämta information från en databas. Koden exekveras på serversidan och all utskrift skickas ned till webbläsaren tillsammans med html-koden. PHP används dock inte bara till webbsidor utan det går även att använda direkt via konsolen[14]. 7 3 3.1 Forskningsfrågor och metodik Frågeställningar Arbetet ska försöka att besvara följande frågor: RQ1. Vilka jämförelser av Sql och NoSql-databaser finns redan och hur utformades de? RQ2. Vilken databas presterar snabbast när det gäller att sätta in och filtrera data? RQ3. Blir det några skillnader på resultatet vid annan uppsättning av miljö? Listan nedan visar vilka metoder respektive fråga kommer att besvaras med: RQ1. Forskning i litteratur RQ2. Experiment/tester RQ3. Experiment/tester 3.2 Utformining av litteraturstudie Sökning efter lämplig litteratur genomfördes under ett antal dagar och resulterade i en lista med artiklar av olika slag, men även guider och länkar till givande webbsidor hittades. Resultaten hittades uteslutande på internet med hjälp av följande sökmotorer: – Google schoolar – BTH Summon – Google De söktermer som användes var: – – – – – – – – Nosql nosql, mysql vs nosql Comparison between NoSQL and mysql paper nosql mysql nosql performance mysql performance mysql nosql php perspective prestandaskillnader nosql mysql De kriterier som fanns för att godkänna en artikel var att den måste vara publicerad senare än 2008 och att artikeln ska innehålla något som rör någon av databastyperna. Anledningen till att de inte ska vara äldre än från 2008 beror på att även om Nosql funnits länge, är det de senaste åren som det blivit ett väldigt hett ämne och blivit ett alternativ för tjänster med stora mängder data. Äldre artiklar kan även innehålla irrelevanta saker, till exempel funktionalitet som då inte fanns tillgänglig men gör det nu. 4 Resultat från litteraturstudie Nedan beskrivs litteraturen från litteraturstudien(sektion 4.1) och vilka av de funna artiklarna som relaterar till vilken forskningsfråga(tabell 2) I sektion 4.2 presenteras även resultaten som sedan diskuteras utifrån studien. 8 4.1 Beskrivning av litteratur Tabell 1 visar artiklarna från litteraturstudien där blått symboliserar arbeten skrivna av studenter(33%), grönt är papper som publicerats i konferenser(42%) och de som är markerade med orange är övriga artiklar såsom guider eller artiklar publicerade på internet(25%). Det som är gemensamt för alla artiklar är att de handlar om MySql, NoSql eller något som relaterar till dem. Vi har försökt finna och välja ut de som antingen handlar om prestanda eller de som jämför databastyperna på något sätt och som inte är utgivna tidigare än 2008. Som sökmetod för att hitta artiklar användes internet, genom de sökmotorer som nämnts i sektion 3.2. Den funna artikelns sammanfatting låg till grund för att avgöra om den var relevant eller inte. Artikel Rubrik Ref. P1 Document Oriented NoSQL Databases - A comparison of performance in MongoDB and CouchDB [3] using a Python interface P2 Utredning av NoSQL-databaser för Sogeti i Gävle [15] P3 Data modeling with NoSQL: how, when and why [16] P4 Building blocks of a scalable web crawler [17] P5 Will NoSQL databases live up to their promise? [18] P6 Debunking the NoSQL Hype [19] P7 Security Issues in NoSQL Databases [20] P8 Using MongoDB to Implement Textbook Management System instead of MySQL [21] P9 MySQL Performance Analysis on a Limited Resource Server: Fedora vs. Ubuntu Linux [22] P10 MySQL & NoSQL from a PHP Perspective [23] P11 Getting Started with MongoDB and PHP [24] P12 Schema-Free MySQL vs NoSQL [25] Tabell 1: Funna artiklar i litteraturstudie 4.2 Resultat och diskussion Det var svårt att hitta artiklar som jämför MySql och NoSql men det ser vi som positivt eftersom detta arbete blir mer betydelsefullt och kan ge mer värde. Det visade sig vara enklare att hitta artiklar om NoSql än MySql, som inte är för gamla, men vi har ändå lyckats få med båda typerna i vår litteraturstudie. Den första artikeln(P1) som testar MongoDb och CouchDB gjorde också att MongoDb valdes som den databas vi ska testa emot MySql, eftersom den var snabbare på de tester som gjorts[3]. Tabell 2 visar vilka artiklar från litteraturstudien som är relevanta för respektive forskningsfråga. 9 Fråga Relaterade artiklar RQ1. P1[3], P2[15], P4[17], P5[18], P8[21], P12[25] RQ2. P1[3], P2[15], P8[21] RQ3. P2[15], P9[22] Tabell 2: Artiklar relaterade till forskningsfrågor 4.2.1 RQ1. Vilka jämförelser av Sql och NoSql-databaser finns redan och hur utformades de? Tabell 2 visar att det finns ganska många artiklar som på något sätt jämför Sql med NoSql. De flesta artiklar som jämför databaser handlar om samma databastyp, dvs NoSql vs NoSql eller SQL vs SQL. I de flesta av de artiklar som hittats ligger inte fokus på själva jämförelsen mellan SQL och NoSql men den är oftast nödvändig för att ge läsaren tillräkligt med bakgrundskunskap om skillnaderna mellan dem. I sådana artiklar görs heller inga detaljerade experiment mellan databastyperna utan jämförelsen består mestadels av ren fakta. Henricsson[3] jämför de två NoSql-databaserna MongoDb och CouchDB och för att göra det krävs att läsaren har viss kunskap kring både NoSql och Sql. Därför ges detta som bakgrund innan experimenten genomförs. Söderberg och Eriksson[15] utför inte heller några experiment när det gäller jämförelse av Sql och NoSql. Arbetet är främst utformat som en litteraturgranskning där de tar upp skillnader mellan NoSql-databaser men även mellan NoSql och Sql. De tar upp för och nackdelar för de olika databaserna och diskuterar vilka användningsområden som lämpar sig för respektive typ. Arbetet innehåller även information om skalbarhet mellan de olika databaserna, detta är dock inte något som detta arbete kommer att lägga fokus på. MySql’s styrka med relationer skapar en svaghet för bland annat webbapplikationer, där hög prioritet är att man kan hämta ned data snabbt ur databasen. Till detta ändamål kan en NoSql-databas vara mer lämpligt att använda. I vårt arbete är det viktigt att testerna inte är “partiska” till en viss databastyp. Syftet med Seegers[17] arbete är att bygga en skalbar sökrobot för webben. För att kunna implementera en sådan genomförs först en omfattande utvärdering av olika verktyg och även en mängd olika databaser. Bland dem finns både MongoDb och MySql, men det görs ingen direkt jämförelse mellan dem. Denna utvärdering kan vara mycket relevant för vårt arbete. Alla utvärderingar bygger på fakta ifrån andra studier som sedan ligger till grund för valet av de verktyg som ska användas för sökroboten. Segeer kommer fram till att MongoDb inte kan användas eftersom molnmiljön där applikationen är tänkt att köras använder ett 32-bitars operativsystem. MongoDb har nämligen en storleksbegränsning på 2Gb i ett 32-bitars system[26]. För att bygga sökroboten används istället MySql som databas. Detta är för att MySql lätt kan integreras mot andra system som är nödvändiga. Detta arbete kommer att utföra experiment med MongoDb på både 32 och 64-bitars os för att se vad skilladerna blir. Artikel P5 är skriven av Neal Leavitt[18] och är utformad som en tidningsartikel. Inte heller denna artikel utför några experiment. Istället används intervjuer men även fakta och historia som huvudsakliga källor. Leavitt tar upp för och nackdelar med både Sql och NoSql-databaser. Sql-databaser kan bli långsamma om de använder komplex tabellstruktur och att använda sql där datatyper kan variera, är inte lämpligt eftersom sql är utformat för att användas med strukturerad data. Leavitt kommer fram till att NoSql-databaser inte kan ersätta relationsdatabaser men är ett bra alternativ för vissa typer av projekt, till exempel när skalbarhet är viktigt för databasen. Skalbarhet kommer inte att testas i vårt arbete. I den genomförda litteraturstudien hittades någon enstaka artikel vars syfte är att jämföra SQL - NoSql som också innehåller experiment för detta. En artikel utför experiment som går ut på att ersätta MySql 10 med MongoDb i ett system för att hantera böcker[21]. Det är dock ett relativt litet arbete som utför tester för insättning och filtrering med en datamodell för MongoDb som har relationer likt modellen för MySql. Därmed missar de en del av poängen med NoSql-databaser som inte behöver använda relationer för att på så sätt öka snabbheten. De båda databaserna sätts upp med tabeller/samlingar med likvärdig data, sedan testas prestanda genom att sätta in 100000 element och filtrera ut 2000 element av dessa. Exemplet på hur MongoDB kan ersätta MySQL är relevant för våra tester så att resultaten kan jämföras. Grigorik[25] visar att det går att använda MySql på liknande sätt som NoSql-databaser, d.v.s. utan fördefinierad struktur. Detta är en intressant synvinkel som inte stötts på i någon tidigare artikel. Han menar att MySql har en väldig styrka med relationer, speciellt med databasmotorn InnoDB. Genom att använda MySql-databasen utan schema bevaras denna stryka samtidigt som den inte bryr sig om strukturen för de element som ska sättas in, likt NoSql. 4.2.2 RQ2. Vilken databas presterar snabbast när det gäller att sätta in och filtrera data? Fråga två kommer dels att besvaras genom de experiment som genomförs men litteraturen är också en viktig del för att förklara resultatet och eventuella skillnader samt att kunna stukturera upp detta arbetes experiment. Henricsson[3] utför tester mellan de två databaserna CouchDb och MongoDb. För att ge MySql en värdig motståndare, är detta ett bra arbete för att hitta en snabb databas av typen NoSql. De tester som genomförts är insättning av data samt filtrering av olika slag. Testerna liknar, till stor del, de som kommer att genomföras i vårt arbete och ger därför en hel del relevant information hur experiment för databaser kan genomföras. Resultatet från Henricssons arbete visar att MongoDb var betydligt snabbare och vann i stort sett alla tester som genomfördes. Utifrån detta resultat har vi valt just MongoDb som motståndare till MySql. I den litteraturgranskning som Söderberg och Eriksson[15] genomfört vägs de bägge koncepten, NoSql och Sql, mot varandra ur olika perspektiv. Eftersom inga tester genomförs i arbetet går det inte rikitgt att avgöra vilken av databaserna som prestarar snabbast. De säger dock att NoSql är snabbare, speciellt vid filtrering. Eftersom vårt arbete kommer genomföra tester för detta kan vi kanske ge svar på om detta stämmer eller inte. En anledning till att NoSql är snabbare är att datamodellerna oftast är mycket simplare. De har även med lite benchmarking om prestanda där de bl.a. säger att Cassandra kan skriva till ett datalager som tar upp 50 GB på disken på 0,12 millisekunder, mer än 2 500 gånger snabbare än MySQL. Med detta som grund kan vi då fråga: är även MongoDb snabbare än MySql? Wei-ping m.fl[21] kommer fram till att MongoDb är snabbare än MySql, även om testerna använder relationer. Detta visar att relationer i MongDb kanske kan vara bra att använda där det behövs. Arbetet är det enda vi hittat som jämför just MySql och MongoDb, dessutom är det ganska litet. I vårt arbete kommer vi genomföra fler tester och även testa MongoDb utan att använda relationer, för att se om det blir några uppenbara skillnader. 4.2.3 RQ3. Blir det några skillnader på resultatet vid annan uppsättning av miljö? Precis som tidigare fråga så kommer fråga tre att besvaras med hjälp av experiment, men även att studera de artiklar som handlar om prestanda (se relaterade artiklar i tabell 2). Söderberg och Eriksson[15] har även en del information om prestanda. Minne och lagring hanteras inte likadant mellan olika databaser och därför är det viktigt att ha rätt hårdvara. De tar upp fördelar med att använda SSD(Solid-state drive), som antagligen ger snabbare resultat för både Sql och NoSql. Söderberg och Eriksson tar också upp problem kring relationsdatabaser som lagrar stora mängder data där risken för långsamhet är stor. Ett sätt att förbättra prestandan är då att uppgradera hårdvaran. Däremot är det betydligt 11 enklare att skala en NoSql-databas över flera datorer istället för att lägga pengar på en enda dator med extrem hårdvara. Självklart påverkas resultatet av vilken hårdvara som används. För att visa det kommer vi även att utföra alla tester på olika datorer, med olika hårdvara och opertivsystem. Experimenten i artikel P9[22] testar prestanda i MySql och utfördes som en klient-server applikation. Testerna gick ut på att använda transaktioner för att utföra operationer med 10000, 50000 och 100000 rader i tabellerna. Under tiden mättes prestanda i TPS(Transactions Per Second). För varje test ökade de antalet trådar att använda för att på så sätt utreda hur stor påverkan det har på resultaten. De slutatser man kan dra utifrån arbetet är att val av operativsystem och inställningar påverkar prestandan mycket. MySql server presterar snabbare på Ubuntu 8.04 än Fedora 8 i de flesta situationer. Antalet trådar som används har stor inverkan på cpu och minnesanvändning. Resultaten kan vara värdefulla när vi utvärderar prestandaskillnader mellan MySQL och NoSQL. 5 Utformining av experiment 5.1 Mål Målet med de experiment som ska genomföras är att ta reda på vilken databas som snabbast sätter in data samt filtrerar data. Givetvis täcker inte de definierade testerna alla olika scenarion som finns men kommer fortfarande att ge en bra bild över hastighetsskillnaderna mellan databaserna. Testerna kommer även att testas på två datorer för att se om ytterligare skillnader uppstår vid olika uppsättningar av miljö. 5.2 Faktorer Nedan följer faktorer som kan påverka resultetet av experimenten och hur de hanteras. 5.2.1 PHP Varje databas har sina egna funktioner för att beräkna tid för olika operationer. För att minimera risken att de mätningar som ska utföras blir till fördel för en viss databas har vi tagit beslutet att inte använda dessa funktioner. Istället kommer vi använda unix-kommandot time, men då krävs att experimenten kan köras som ett kommando ifrån en unixterminal där man undviker steget att först starta databasens administrationsgränssnitt. För att lösa detta problem kommer php att användas som scriptspråk. Därmed medförs också faktorn att scriptet i sig använder en viss tid, vilket i sin tur gör att databasens tid inte blir exakt. Att tillverka scriptet så att det inte använder någon tid alls är helt omöjligt. Därför kommer php-scriptet att göras så litet som möjligt och vi kommer att se till att scriptets tid varierar minimalt från gång till gång. Vi kommer även att köra varje test 5 gånger och sedan räkna ut medelvärdet för varje testfall och på så vis minimera scriptets påverkan på resultatet. 5.2.2 Operativsystem & Hårdvara Val av operativsystem och hårdvara kan ha stor påverkan på testresultaten. Experimenten kommer därför att köras på två olika datorer med olika versioner av os. De operativsystem som valts är Ubuntu GNU/Linux 10.04 LTS 32 respektive 64 bitarsversion eftersom Ubuntu var det os som presterade bäst i jämförelse med fedora[22]. Specifikationer för respektive dator som kommer att användas finns under sektion 5.3.1 Systeminformation. 12 5.2.3 Olika datamodeller Eftersom MySql är en relationsdatabas och MongoDb är en NoSql-databas utan relationer, finns risken att resultaten kan bli felaktiga och orättvisa eftersom datamodellen kommer att se olika ut för respektive databas. MongoDb har dock ett sätt att hantera relationer, där man istället för att spara själva värdet i en array i objektet, sparar en referens till ett annat objekt i databasen i en likvärdig array. Eftersom dessa två varianter finns att bygga upp datamodeller på i MongoDb, kommer även relations-varianten att testas i detta arbete. Exerimenten kommer innehålla att spara ned bilder i databaser, och MongoDb innehåller ett speciellt system för att spara ned filer som kallas för gridFs, och finns beskrivet i sektion GridFs 2.3.1. Tester kommer därför att genomföras både med och utan gridFs för att se ifall det har någon större påverkan. 5.2.4 Datamängder En annan faktor som kan påverka resultatet vid insert är om databasen redan innehåller data när testerna körs. Det kan t.ex. vara så att det tar längre tid för databasen att sätta in ett nytt element om databasen inte är tom. Detta arbete kommer inte att utföra några experiment som tar hänsyn till denna faktor. Vi anser att påverkan är minimal och därför kommer denna typ av tester endast att utföras på tomma databaser. 5.2.5 Vad för typ av data Insättning av olika typer av data kan påverka tiden, och för att ta reda på skillnader det kommer tester att genomföras där både databasen får lagra nummer, strängar samt bilder i binär form. 5.2.6 Sätta in all data samtidigt Både MySql och MongoDb har stöd för att sätta in all data i en enda förfrågning, istället för att göra en förfrågning per objekt som ska läggas till. Experiment kommer utföras både med och utan detta och se eventuella skillnader både mellan typerna och inom samma databas. 5.3 Testmiljö Genereringen av testdatan kommer att skötas från en ny funktion i ett php-skript och den data som kommer att skapas finns definierad under sektionen Datamodell 5.4. Givetvis kommer detta att påverka den slutgiltiga tiden för exekveringen, men då båda databaserna kommer att få denna extratid, kan den ignoreras vid jämförelse av resultatet. För att alltid samma data ska genereras, har vi statiskt angett ett specifikt srand-värde. För att mäta tiderna kommer Unix-kommandot time att användas. Anledningen till att använda detta istället för tiden som man direkt kan få ut från MySql och MongoDb, är att vi vill kunna använda samma tidsfunktion till båda databas-typerna. Detta för att minimera felmarginaler för tiden man kan få fram från respektive databas, då vi inte kan säkerställa att tiden räknas ut på exakt samma sätt. Varje enskild mätning kommer att göras fem gånger, och sedan kommer medelvärdet att räknas ut. Real: Den faktiskta tiden det tar att exekvera ett kommando, som att använda ett stoppur. User: Visar CPU-tiden, spenderad i "user mode". Sys: Visar tiden, spenderad i kärnan, "Kernel". Den tid som kommer att användas under experimenten i detta arbetet är Real. 13 5.3.1 Systeminformation Mjukvaran är densamma för båda datorerna förutom operativsystemet: PHP: 5.3.5 MySql: 5.1.62 MongoDb: 2.0.5 Dator 1: Operativsystem: Ubuntu GNU/Linux 11.04 64 bit Processor: AMD Dual Core 3GHz Minne: 4 GB Dator 2: Operativsystem: Ubuntu GNU/Linux 11.04 32 bit Processor: Intel Core 2 Duo 2.67GHz Minne: 2 GB 5.4 Datamodell Datamodellerna skiljer sig åt mellan de experiment som ska göras. För insättning kommer det finns två olika tabeller, en för Medlemmar där strängar kommer sparas, samt en bild-tabell där bilder i binär form lagras. MongoDb kommer även testas med gridFs som finns beskrivet under sektion GridFs 2.3.1. Vid testerna för filtrering kommer Mysql ha tabeller för produkter och kategorier, vilket skapar ett många till mångaförhållande. Även här kommer MongoDb innehålla två olika lösningar, en helt fri från relationer med endast en tabell och en annan variant med två tabeller. Tabeller med en överblick hur databasmodellen ser ut både för insättning och filtrering finns i bilaga A. 6 Utförande RQ2 och RQ3 kommer att besvaras genom experiment. Två datorer med olika hårdvara och operativsystem har satts upp för att kunna genomföra tester med både MySql och MongoDb. Under sektion 5.3.1 Systeminformation, specificeras hårdvaran samt operativsystem som kommer att användas för respektive dator. Databaserna kommer att testas med hjälp av ett php-skript. Kommandot för att exekvera php-sriptet som gör en insättning på 10000 rader i MySql ser ut såhär: time php insertMySql.php -n 10000 -t i 6.1 Testfall Tabellerna nedan visar alla testfall som ska utföras. Varje testfall kommer att köras fem gånger och sedan ska medelvärdet av resultaten räknas ut. Detta för att tiderna kan variera mellan varje körning. 14 6.2 Insättning Tabell 3 visar testfallen för instättning där två olika datatyper kommer att användas: Member och Image (För mer inormation om datamodellerna se bilaga A.1 och A.2). Experiment kommer också att utföras med multiinsättning (sektion 2.4 Multiinsättning) för 100 000 members och fler. Anledningen till att färre antal inte kommer att testas med detta är att det handlar om så små mängder så multiinsättning inte anses relevant. Kolumnen “antal” anger hur många element som ska sättas in för varje test. TestId Dator Datatyp Multiinsättning Antal 1 Ubuntu 64 Member nej 1000 2 Ubuntu 64 Image nej 1000 3 Ubuntu 64 Member nej 10 000 4 Ubuntu 64 Image nej 10 000 5 Ubuntu 64 Member nej 100 000 6 Ubuntu 64 Member ja 100 000 7 Ubuntu 64 Member nej 1 000 000 8 Ubuntu 64 Member ja 1 000 000 9 Ubuntu 32 Member nej 1000 10 Ubuntu 32 Image nej 1000 11 Ubuntu 32 Member nej 10 000 12 Ubuntu 32 Image nej 10 000 13 Ubuntu 32 Member nej 100 000 14 Ubuntu 32 Member ja 100 000 15 Ubuntu 32 Member nej 1 000 000 16 Ubuntu 32 Member ja 1 000 000 Tabell 3: Samtliga tester som kommer genomföras för insättning 15 6.3 Filtrering Tabell 4 visar alla testfall som ska köras för filtering. I dessa tester ska används datamodellerna för produkt och kategori som finns beskrivna i bilaga A.3 och A.4. I dessa tester ska alla produkter med en viss kategori filtreras ut. För MongoDb finns två sätt att hantera modellen, antingen med relation till en annan collection, eller att all data finns i en array direkt hos objektet. Tester kommer därför att utföras för båda varianterna. Kolumnen “antal” i tabellen nedan visar hur många element som finns i databasen, som därmed behöver sökas igenom för varje test. TestId Dator Antal 17 Ubuntu 64 1000 18 Ubuntu 64 10 000 19 Ubuntu 64 100 000 20 Ubuntu 64 1 000 000 21 Ubuntu 64 4 000 000 22 Ubuntu 32 1000 23 Ubuntu 32 10 000 24 Ubuntu 32 100 000 25 Ubuntu 32 1 000 000 26 Ubuntu 32 4 000 000 Tabell 4: Samtliga tester som kommer genomföras för filtrering 16 7 Resultat Nedan presenteras resultat från alla tester som genomförts. De tester som är rödmarkerade är sådana som av någon anledning inte kunde fullföljas. De tider som är skrivna med grön text visar den snabbaste tiden för testet. Varje test kördes fem gånger där tiden mättes varje gång, sedan räknades medelvärdet av dessa tider ut och det är den tiden som visas i tabellerna nedan. Alla tider är angivna i sekunder. 7.1 Insättning Tabell 5 och 6 visar resultat för insättning av medlemmar och bilder på de olika datorerna. Kolumnen “Antal” anger hur många element som sattes in i databasen vid respektive test. Vid insättning av bilder genomfördes ett ytterligare test med GridFs för att se om det blev några skillnader. Tabellen visar att användandet av GridFs gjorde att tiden ökade med några sekunder. MongoDb visade sig vara snabbare på de flesta testerna förutom de som använde multiinsättning (sektion 2.4 Multiinsättning). Test nummer 8 och 16 kunde inte genomföras för MongoDb på grund av det finns en 16mb-spärr för objektens storlek. Denna spärr kunde inte heller konfigureras. 7.1.1 Ubuntu 64 TestId Datatyp Antal Multi MySql MongoDb 1 Member 1000 nej 0,146 0,122 2 Image 1000 nej 3,859 1,353 3 Member 10 000 nej 0,712 0,310 4 Image 10 000 nej 43,515 50,170 5 Member 100 000 nej 7,214 3,157 6 Member 100 000 ja 0,874 2,388 7 Member 1 000 000 nej 65,868 34,687 8 Member 1 000 000 ja 7,120 0 Tabell 5: Resultat för testerna med insättning på Ubuntu 64 17 GridFs 3,385 53,603 7.1.2 Ubuntu 32 Testerna med GridFs för bilder kunde inte slutföras på grund av storleksbegränsningen för lagring i MongoDb på 2Gb på ett 32-bitarssystem. TestId Datatyp Antal Multi MySql MongoDb 9 Member 1000 nej 0,079 0,048 10 Image 1000 nej 4,693 0,788 11 Member 10 000 nej 0,479 0,299 12 Image 10 000 nej 47,207 18,327 13 Member 100 000 nej 4,432 1,720 14 Member 100 000 ja 0,544 1,763 15 Member 1 000 000 nej 43,965 17,745 16 Member 1 000 000 ja 5,138 0 GridFs 0 0 Tabell 6: Resultat för testerna med insättning på Ubuntu 32 7.2 Filtrering Tabell 7 och 8 visar resultat från experimenten med filtrering av data. Kolumnen “Antal” anger hur många element som fanns i databasen när testen utfördes och som därmed filtrerades. Eftersom det finns två varianter på att hantera datamodellen i MongoDb testades båda två. Kolumnen “MongoDb Relationer” visar resultaten från testerna med separata collections för relationer mellan produkt och kategori. Kolumnen “MongoDb” visar resultaten från testerna utan relationer. Även här visade det sig att MongoDb är snabbare än MySql och att använda MongoDb utan relationer är snabbast. 7.2.1 Ubuntu 64 TestId Antal MySql MongoDb Relationer MongoDb 17 1000 0,085 0,081 0,076 18 10 000 0,136 0,135 0,120 19 100 000 0,486 0,457 0,416 20 1 00 000 20,616 3,009 2,344 21 4 000 000 82,427 11,826 8,546 Tabell 7: Resultat för testerna med filtrering på Ubuntu 64 18 7.2.2 Ubuntu 32 TestId Antal MySql MongoDb Relationer MongoDb 22 1000 0,040 0,036 0,036 23 10 000 0,080 0,051 0,049 24 100 000 0,500 0,208 0,181 25 1 000 000 23,490 1,874 1,600 26 4 000 000 96,136 16,061 14,898 Tabell 8: Resultat för filtrering med insättning på Ubuntu 32 8 Analys och diskussion Experimentresultaten är väldigt intressanta, de flesta var väntade, men vid insättning var faktiskt MySql snabbare än MongoDb när multi-insert användes. Graferna nedan visar hur resultatet påverkades av antalet element som sätts in eller filtreras. Fler diagram och större format finns i bilaga C. 8.1 Tester som inte kunde genomföras Tabellerna visar att det var några experiment som inte gick att fullfölja. Anledningen till att test 8 och 16 fallerade på MongoDb är att det finns en gräns för objektens storlek på 16mb. Dokumentationen för MongoDb säger att denna begränsning gäller på de enskilda objekten som sparas i databasen. Så verkar dock inte vara fallet utan beräkningen görs på den data som faktiskt skickas till socketen. Detta bekräftas i ett ärende[27] som finns publicerat på Github där MongoDb’s kod finns uppladdad. Experimentet som genomfördes i detta arbete, skulle sätta in ett visst antal element som en så kallad bulk-insert. Vilket betyder att alla element skickas till databasen i en enda request som MongoDb sedan hanterar och lagrar som många objekt. Två dagar innan testen genomfördes släpptes en fix för detta problem men den php-driver som detta arbete använder sig av, verkar inte ha lagt in stöd för detta ännu. Även MySql har en gräns på 16mb men denna kan lätt utökas via en konfigurationsfil, vilket gjordes för experimentet. De två andra testerna som inte kunde genomföras var insättning av bilder i gridFs på datorn med Ubuntu 32. Alla de tidigare testerna hade slutförts men när dessa skulle köras, uppstod fel som: MongoDb : can ' t map f i l e memory − mongo r e q u i r e s 64 b i t build for larger datasets Vi var medvetna om gränserna på ett 32-bitars system men då borde inte heller de tidigare testerna med bilder fungerat. Felen började istället uppstå efter att datorn startats om och det är fortfarande oklart varför problemen uppkom just då och inte tidigare. Det gjordes ett par försök att reparera databasen, vilket även lyckades en gång men problemet återuppstod ganska snart, så dessa tester fick tyvärr avbrytas. 19 8.2 Analys av resultatet Figur 2 visar tidsskillnaderna mellan MySql och MongdoDb vid insättning. Diagrammet visar tydligt att MySql tar längre tid på sig än sin konkurrent, speciellt vid insättningen av det högsta antalet element som var 1000000st. MongoDb sätter in medlemmarna på drygt 35 sekunder där Mysql gör det på 66 vilket anses som en betydlig ökning. 70 MySql MongoDb 60 Tid(s) 50 40 30 20 Det är emellertid inte vanligt att databasen behöver hantera denna typ av insättning med så mycket samtidig data. Resultatet för insättning av, upp till drygt tiotusen members, ligger på mindre än en sekund för båda databaserna vilket inte anses speciellt mycket. 10 0 1000 10000 100000 10000000 Antal Figur 2: Ubuntu 64, Insättning av data Det som däremot går snabbare för MySql är om insättningen sker i en så kallad multiinsert(bulk-insert för MongoDb) där all data sätts in med ett anrop. MongoDb klarade inte ens av att genomföra båda testerna på grund av den gräns som finns för objekten. Resultaten för 32-bitarsdatorn visar liknande värden, med samma mönster där MySql tar betydligt längre tid på sig att sätta in större mängder data. Även om det inte är vanligt att sätta in större mängder data på en gång, så är det tvärt om när det gäller hämtning och filtrering av information. Den struktur för tabeller/collections som användes under experimentet var relativt enkel, men ändå kan man se att MongoDb är betydligt snabbare än MySql. Vid filtrering av 4 miljoner produkter skiljer det ungefär 70 sekunder, vilket är en enorm skillnad. Skillnaderna mellan MongoDb med och utan relationer är märkbar, men i detta fallet inte speciellt kritisk, på 4 miljoner data skiljer det sig cirka 3 sekunder vilket inte anses speciellt mycket i jämförelse till Mysql. 8.3 90 MySql MongoDb utan relationer MongoDb med relationer 80 70 Tid(s) 60 50 40 30 20 10 0 1000 10000 100000 10000000 40000000 Antal Figur 3: Ubuntu 64 : Filtrering av data Olika sätt att hantera resultatet MySql och MongoDb skiljer sig på många punkter, bland annat hur de hanterar resultatet som skickas ned till klienten, i detta fall till php-scriptet som hanterar testerna. Det som händer när en sökning görs i MongoDb är att data inte skickas ned direkt till applikationen, istället skickas en pekare till resultatet. Fördelen är att klienten då slipper att spara all information i minnet och kan istället hantera varje enskilt dokument, ett i taget, när så önskas. MySql däremot skickar hela resultatet på en gång, vilket kan bli väldigt dyrt för minnet om det handlar om större mängder data. 8.4 8.4.1 Slutsatser MongDb är snabbare Med få undantag vann MongoDb på samtliga tester som genomfördes för de båda systemen. Det går alltså att vinna mycket tid vid hantering av större mängder data, samtidigt som en viss struktur av relationer mellan collections kan finnas likt MySqls tabellrelationer. Det största testet som genomfördes här var dessutom 20 endast på 4 miljoner vilket kan ses som väldigt lite i jämförelse till Facebook[1] som i april detta året hade över 900 miljoner aktiva användare[28]. Att göra experiment på sådan stor mängd data skulle med stor sannolikhet styrka argumenten till att använda MongoDb istället för MySql. 8.4.2 MongoDb på ett 32-bitars system Begränsningarna att köra MongoDb på ett 32-bitarssystem nämns kortfattat på MongoDb’s officiella hemsida[26]. De experiment som genomförts i detta arbete kan bekräfta att databasen inte bör användas på ett 32-bitars system. Databasen kraschade även om testerna höll sig inom gränserna och det finns egentligen inga garantier att det går att reparera eventuella fel som uppstår, så att datan kan återställas och fortfarande användas. Det finns många forum på internet med inlägg av personer som har haft liknande problem och den enda egentliga lösningen som de kommit fram till är att köra MongoDb på ett 64-bitarssystem. 8.5 Validering av resultat Experimenten har inte körts i något realtidssystem och de tider som presenteras i tabellerna är ett medelvärde från fem körningar. Varje test körs aldrig exakt på lika lång tid utan det varierar från gång till gång. Här är det många faktorer som spelar in, till exempel den nuvarande belastningen på datorn. Även den php-kod som använts för att kommunicera med databaserna påverkar sluttiden då det alltid finns småsaker som aldrig går exakt lika fort. Detta uppstår för de båda databasernas tester och på så sätt är det ingen direkt fara att detta inträffar, det är fortfarande möjligt att jämföraMongoDb och MySql. Resultaten mellan de olika datorerna kan vara missvisande då tiderna var allt för lika på de allra flesta experimenten. Det fanns ett antagande att dator två skulle genomföra testerna långsammare med tanke på halverat ram-minne, men troligtvis jämnade det ut sig med processorn som den hade och fick istället något snabbare resultat än den första datorn. Rent hårdvarumässigt vore det klokare att ha större skillnader på hårdvaran, för att kunna dra några slutsatser. 8.6 Kopplingar till tidigare arbeten Litteraturstudien visar att intresset för NoSql-databaser är stort, dock visade det sig att rena jämförelser mellan SQL och NoSql inte förekom speciellt ofta. Anledningen till detta är antagligen att NoSql fortfarande är ett relativt nytt begrepp i databasvärden. Det märktes också i de tester som utfördes, att MongoDb inte är lika pålitiligt som MySql, vilket kan bero på att MongoDb är så pass nytt. Resultaten i detta arbete kan bekräfta ett tidigare arbete som visar att MongoDb är snabbare än MySql[21], åtminstone i de fall som dessa experimenten täcker. Det stärker även påståenden om att NoSql-databaser generellt är snabbare än relationsdatabaser[18]. Detta arbete har dock inte alls fokuserat på säkerhet i databaserna, men det finns svagheter i NoSql som är viktiga att ta i beaktning[20]. Oracle publicerade en artikel som vi trodde skulle ta upp och diskutera nackdelar med NoSql[19]. Det visade sig dock att artikeln mest handlade om att lyfta upp fördelar med Oracles lösningar och inte så mycket om generella brister med NoSql. 8.7 Framtida arbete Databasstrukturen som användes under jämförelse av filtrering är bara ett av många olika fall där man är i behov av någon form av relationer. Att utföra tester med ytterligare och mer avancerade relationer hade varit intressant då man åter kan se styrkan med MongoDb’s snabbhet där MySql inte riktigt hänger med. Ett exempel på en lite mer avancerad relation är att ha en separat tabell för pris, som läggs till i strukturen för produkter och kategorier som användes i detta arbete. Då skulle denna tabell hantera daglig historik för produktens prisutveckling. Om det t.ex. finns totalt 5000 produkter och en historik med prisutveckling för 21 60 dagar så finns totalt 300000 raders historik. Ett testfall skulle då kunna vara att lista alla produkter med dess kategorier och det senaste priset, eller visa prisutveckling för produkterna den senaste månaden. Tiden borde, rent teoretiskt sett, öka drastiskt. Figur 4: Exempel hur en relation mellan produkter, kategorier och pris kan se ut. Det hade även varit intressant att göra ytterligare tester mellan olika datorer, men då med större skillnader på hårdvara än de system som detta arbete använt sig av. Att det inte rekommenderas att köra ett 32-bitars system för MongoDb är ett faktum, som även de tester som genomförts i detta arbete kan bekräfta. Det vore därför bättre om man använder 64-bitar på alla de system som ska jämföras. Mer fokus bör läggas på den faktiska hårdvaran och inte bara ta hänsyn till hur mycket minne utan även hastigheten på dem. Förutom ram och processor bör även hastighet och vilket filsystem som håddiskarna använder sig av, tas hänsyn till. Ett annat experiment skulle kunna vara att testa databaserna på 32 vs 64-bitarssystem som har exakt samma hårdvara för att på så sätt redogöra alla skillnader som enbart beror på denna faktor. Dock lämpar sig detta inte för stora mängder data eftersom MongoDb då inte kan testas fullt ut. 9 Sammanfattning I de fallen som detta arbetet täcker visar att vid byte från MySql till MongoDb är det möjligt att få en betydligt snabbare databas, med en relativt lik struktur. Tiden för filtrering av 4 miljoner produkter för Ubuntu 64 (tabell 7) skiljer sig drygt 70 sekunder mellan databaserna och sedan är den helt relationsfria lösningen för MongoDb några sekunder snabbare. Testerna visar dock att skillnaderna mellan lösningen med och utan relationer för MongoDb inte är nämnvärt stor så i detta fallet vinner man nog mer att köra alternativet med relationer, då det till exempel räcker att byta kategori-namn på ett ställe istället för på varje enskild produkt tack vare kopplingen med id-nummer. Det är dessutom väldigt lätt att komma igång med MongoDb, precis som för Mysql finns det stöd till de allra flesta populära programspråken[29]. Även om det kanske inte finns någon direkt anledning använda Mysql i de fallen som exerimenten innehöll så finns det dock fortfarande fördelar att hålla sig kvar vid MySql. Även om det finns ett visst stöd för relationer i MongoDb så finns det inte alls lika mycket funktionalitet som MySql innehåller, vilket just är 22 en av idéerna med en icke relationsdatabas. Det kan finnas de fall då det är nödvändigt att använda sig av bland annat främmande nycklar för att säkerhetsställa att databasen är konsistent, och då är det fortfarande MySql som bör användas. Mysql har även funnits ute längre, så alla dessa problem som nya program kan innehålla är lösta, samtidigt som kompetensen kring detta är större än för MongoDb. Ett problem är ju till exempel begränsningen på 16mb vid insättning av data vilket helt enkelt inte är godtagbart, men troligtvis är det något som kommer att lösas inom kort. 23 Referenser 1. Facebook. http://facebook.com. 2. Twitter. http://twitter.com. 3. Robin Henricsson. Document Oriented NoSQL Databases - A comparison of performance in MongoDB and CouchDB using a Python interface. http://www.bth.se/fou/cuppsats.nsf/all/32737dee280f07ddc12578b200454a24/$file/ BTH2011Henricsson.pdf, 2011. 4. Oracle Corporation. http://www.mysql.com/. 5. Oracle Corporation. SELECT Syntax. http://dev.mysql.com/doc/refman/5.6/en/select.html. 6. Oracle Corporation. FOREIGN KEY Constraints. http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html. 7. 10gen, MongoDb. MongoDb. http://www.mongodb.org/. 8. Bsonspec.org. Bson. http://bsonspec.org/. 9. 10gen, MongoDb. Object IDs. http://www.mongodb.org/display/DOCS/Object+IDs. 10. 10gen, MongoDb. GridFs. http://www.mongodb.org/display/DOCS/GridFS. 11. 10gen, MongoDb. Bulk inserts. http://www.mongodb.org/display/DOCS/Inserting#Inserting-Bulkinserts. 12. D. Crockford. The application/json Media Type for JavaScript Object Notation (JSON). http://www.ietf.org/rfc/rfc4627.txt, 2006. 13. The PHP group. http://php.net. 14. The PHP group. Using PHP from the command line. http://php.net/manual/en/features.commandline.php. 15. Natalja Söderberg/Jan Eriksson. Utredning av NoSQL-databaser för Sogeti i Gävle. http://juseknew.episerverhotell.net/upload/PDF/diverse/NoSQLdatabaser.pdf, 2010. 16. Carlos André Reis Fernandes Oliveira da Silva. Data Modeling with NoSQL: How, When and Why. http://repositorio-aberto.up.pt/bitstream/10216/61586/1/000148158.pdf, 2011. 17. Marc Seeger. Building blocks of a scalable webcrawler. http://blog.marc-seeger.de/assets/papers/thesis_seeger-building_blocks_of_a_scalable_ webcrawler.pdf, 2010. 18. Neal Leavitt. Will NoSQL databases live up to their promise? 2010. http://www.leavcom.com/pdf/NoSQL.pdf. 19. Alan Downing. Debunking the NoSQL Hype. 2011. http://ftp-developpez.com/gordon-fowler/Debunking%20the%20NoSQL%20Hype%20Oracle.pdf. 20. Lior Okman, Nurit Gal-Oz, Yaron Gonen, Ehud Gudes, Jenny Abramov. Security Issues in NoSQL Databases. 2011 IEEE 10th International Conference on Trust, Security and Privacy in Computing and Communications (TrustCom 2011), 2011. 21. Zhu Wei-ping, Li Ming-xin, Chen Huan. Using MongoDB to implement textbook management system instead of MySQL. 2011 IEEE 3rd International Conference on Communication Software and Networks (ICCSN 2011), 2011. 22. Mohiuddin Ahmed, Mohammad Moshee Uddin, Md. Saiful Azad, Shariq Haseeb. MySQL performance analysis on a limited resource server: Fedora vs. Ubuntu Linux. SpringSim ’10 Proceedings of the 2010 Spring Simulation Multiconference, 2010. 23. Tim Juravich. MySQL & NoSQL from a PHP perspective. http://www.slideshare.net/timjuravich/mysql-nosql-from-a-php-perspective, 2011. 24. Vikram Vaswani. Getting Started with MongoDB and PHP. http://devzone.zend.com/1730/getting-started-with-mongodb-and-php/, 2010. 24 25. Ilya Grigorik. Schema-Free MySQL vs NoSQL. http://www.igvita.com/2010/03/01/schema-free-mysql-vs-nosql/, 2010. 26. 10gen, MongoDb. 32 bit limitations. http://blog.mongodb.org/post/137788967/32-bit-limitations. 27. Github. maxBsonSize checked on command, not individual documents. https://github.com/mongodb/node-mongodb-native/issues/609. 28. Mark Hachman. Facebook Now Totals 901 Million Users, Profits Slip. 2012. http://www.pcmag.com/article2/0,2817,2403410,00.asp. 29. 10gen, MongoDb. Drivers. http://www.mongodb.org/display/DOCS/Drivers. 25 A Datamodeller A.1 MySql - Insättning Member Fält Typ Värdemängd firstName Varchar(15) En Sträng mellan 2 och 12 tecken lastName Varchar(15) En Sträng mellan 2 och 12 tecken username Varchar(15) En Sträng mellan 2 och 12 tecken age Int 10-99 Fält Typ Värdemängd id Int 1 till MAX id image MediumBlob Bild i binär form Fält Typ Värdemängd firstName Sträng En Sträng mellan 2 och 12 tecken lastName Sträng En Sträng mellan 2 och 12 tecken username Sträng En Sträng mellan 2 och 12 tecken age Int 10-99 Fält Typ Värdemängd image Sträng Bild i binär form Image A.2 MongoDb - Insättning Member Image 26 A.3 MySql - Filtrering Product Fält Typ Värdemängd id Int 1 till MAX id title Varchar(15) En Sträng mellan 2 och 12 tecken description Text En Sträng mellan 0 och 200 tecken quantity Int Nummer mellan 0 och 1000 Fält Typ Värdemängd id Int 1 till MAX id title Varchar(15) En Sträng mellan 2 och 12 tecken Fält Typ Värdemängd productId Int Id till en existerande produkt categoryId Int Id till en existerande kategori Category ProductCategory 27 A.4 MongoDb - Filtrering A.4.1 Med relationer Product Fält Typ Värdemängd id Int 1 till MAX id title Varchar(15) En Sträng mellan 2 och 12 tecken description Text En Sträng mellan 0 och 200 tecken quantity Int Nummer mellan 0 och 1000 productCategory Array Array med kategorier som innehåller objektId’n till rader som finns i kategori-tabellen Fält Typ Värdemängd title Varchar(15) En Sträng mellan 2 och 12 tecken Fält Typ Värdemängd title Varchar(15) En Sträng mellan 2 och 12 tecken description Text En Sträng mellan 0 och 200 tecken quantity Int Nummer mellan 0 och 1000 productCategory Array Array med kategorier Category A.4.2 Utan relationer Product 28 B Källkod Listing 3: generateData.php <?php define ( " MIN_AGE " , 1 0 ) ; define ( " MAX_AGE " , 9 9 ) ; define ( " MIN_QUANTITY " , 0 ) ; define ( " MAX_QUANTITY " , 1 0 0 0 ) ; define ( " VARCHAR_MIN " , 2 ) ; define ( " VARCHAR_MAX " , 1 2 ) ; define ( " TEXT_MIN " , 0 ) ; define ( " TEXT_MAX " , 2 0 0 ) ; define ( " CATEGORIES_MIN " , 1 ) ; define ( " CATEGORIES_MAX " , 1 0 ) ; define ( " CATEGORY " , "Ee" ) ; define ( " NROFCATEGORIES " , 2 0 0 ) ; define ( 'FILE ' , 'data.txt ' ) ; define ( 'IMAGE ' , 'bth - logga .jpg ' ) ; $ c h a r s = " 0123456789 abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ " ; srand ( 1 2 3 4 ) ; // Generate random string with an exaclty length function rand_string ( $length ) { global $chars ; $ s t r = "" ; $ s i z e = strlen ( $chars ) ; f o r ( $ i = 0 ; $ i < $ l e n g t h ; $ i++ ) { $ s t r .= $ c h a r s [ rand ( 0 , $ s i z e − 1 ) ] ; } return $str ; } // Generate random string between min and max f u n c t i o n rand_string_between ( $min , $max ) { $ l e n g t h = rand ( $min , $max ) ; return rand_string ( $length ) ; } // Generate Member f u n c t i o n generate_member ( ) { $member = array ( ) ; $member [ " firstName " ] = $member [ " username " ] = $member [ " lastName " ] = $member [ "age" ] = r e t u r n $member ; } rand_string_between (VARCHAR_MIN,VARCHAR_MAX) ; rand_string_between (VARCHAR_MIN,VARCHAR_MAX) ; rand_string_between (VARCHAR_MAX,VARCHAR_MAX) ; rand (MIN_AGE,MAX_AGE) ; function generate_category () { 29 } $ c a t e g o r y = array ( ) ; $ c a t e g o r y [ " title " ] VARCHAR_MAX) ; return $category ; = rand_string_between (VARCHAR_MIN, function generate_categories () { $ c a t e g o r i e s = array ( ) ; f o r ( $ i = 0 ; $ i < NROFCATEGORIES; $ i ++) { array_push ( $ c a t e g o r i e s , g e n e r a t e _ c a t e g o r y ( ) ) ; } return $categories ; } function generate_categories_ids () { $nrOfCats = rand (CATEGORIES_MIN, CATEGORIES_MAX) ; $ c a t e g o r i e s I d s = array ( ) ; $count = 0 ; w h i l e ( $count < $nrOfCats ) { $ i d = rand ( 1 ,NROFCATEGORIES) ; i f ( ! in_array ( $id , $ c a t e g o r i e s I d s ) ) { array_push ( $ c a t e g o r i e s I d s , $ i d ) ; $count++; } } return $categoriesIds ; } // Generate product function generate_product ( ) { $ p r o d u c t = array ( ) ; $ p r o d u c t [ " title " ] VARCHAR_MAX) ; $ p r o d u c t [ " description " ] $ p r o d u c t [ " quantity " ] return $product ; } = rand_string_between (VARCHAR_MIN, = = rand_string_between (TEXT_MIN,TEXT_MAX) ; rand (MIN_AGE,MAX_AGE) ; ?> Listing 4: insertMysql.php <?php r e q u i r e _ o n c e ( " generateData .php" ) ; define ( 'DB_HOST ' , 'localhost ' ) ; define ( 'DB_NAME ' , 'thesis ' ) ; define ( 'DB_USER ' , 'thesis ' ) ; define ( 'DB_PASSWORD ' , 'wip ' ) ; $db = new m y s q l i (DB_HOST,DB_USER,DB_PASSWORD,DB_NAME) ; i f ( $db−>c o n n e c t _ e r r n o ) { 30 } die ( " ERROR : Database Connection failed , Mysql Message : " . $ t h i s −>db−> connect_error ) ; // Force Utf -8 communication $db−>s e t _ c h a r s e t ( 'utf8 ' ) ; // Get parameters from commandline $ o p t i o n s = g e t o p t ( "t:n:" ) ; i f ( ! i s s e t ( $ o p t i o n s [ "n" ] ) | | ! i s s e t ( $ o p t i o n s [ "t" ] ) | | ! is_numeric ( $ o p t i o n s [ "n" ]) ) { die ( " ERROR : Optionsparameters is invalid !\n" ) ; } define ( "TYPE" , $ o p t i o n s [ "t" ] ) ; define ( " NROFLOOPS " , $ o p t i o n s [ "n" ] ) ; // Generate data and save to file i f (TYPE == "g" ) { i f ( f i l e _ e x i s t s ( FILE ) ) { u n l i n k ( FILE ) ; } $ h a n d l e = fopen ( FILE , 'w' ) o r die ( 'Cannot open file: ' . FILE ) ; f o r ( $ i =0; $ i < NROFLOOPS; $ i++ ) { $member = generate_member ( ) ; $query = " INSERT INTO Member (firstName , lastName , username , age) VALUES ('" . $member [ " firstName " ] . "', '" . $member [ " lastName " ] . "', '" . $member [ " username " ] . "', '" . $member [ "age" ] . " ');" ; fwrite ( $handle , $query . "\n" ) ; } fclose ( $handle ) ; } i f (TYPE == "gm" ) { i f ( f i l e _ e x i s t s ( FILE ) ) { u n l i n k ( FILE ) ; } $ h a n d l e = fopen ( FILE , 'w' ) o r die ( 'Cannot open file: ' . FILE ) ; $query = " INSERT INTO Member (firstName , lastName , username , age) VALUES " ; f o r ( $ i =0; $ i < NROFLOOPS; $ i++ ) { $member = generate_member ( ) ; $query .="('" . $member [ " firstName " ] . "', '" . $member [ " lastName " ] . "', '" . $member [ " username " ] . "', '" . $member [ "age" ] . " ')," ; } $query = substr ( $query , 0 , −1) ; fwrite ( $handle , $query . "\n" ) ; fclose ( $handle ) ; } // Read from file and insert data to database 31 e l s e i f (TYPE == "i" ) { i f ( ! f i l e _ e x i s t s ( FILE ) ) { die ( " ERROR : Please run setup first to create data file!" ) ; } $ h a n d l e = fopen ( FILE , "r" ) ; i f ( $handle ) { w h i l e ( ( $ b u f f e r = f g e t s ( $handle , 4 0 9 6 ) ) !== f a l s e ) { $db−>query ( $ b u f f e r ) o r die ( $db−>e r r o r ) ; } i f ( ! feof ( $handle ) ) { echo " Error : unexpected fgets () fail\n" ; } fclose ( $handle ) ; // Clear data file echo " Insert complete !" ; u n l i n k ( FILE ) ; } } e l s e i f (TYPE == "im" ) { i f ( ! f i l e _ e x i s t s ( FILE ) ) { die ( " ERROR : Please run setup first to create data file!" ) ; } $ b u f f e r=file_get_contents ( FILE ) ; $db−>query ( $ b u f f e r ) o r die ( $db−>e r r o r ) ; // Clear data file echo " Insert complete !" ; } // Save images e l s e i f (TYPE == "img" ) { i f ( ! f i l e _ e x i s t s (IMAGE) ) { die ( " ERROR : Image not found !" ) ; } $image = chunk_split ( base64_encode ( file_get_contents (IMAGE) ) ) ; f o r ( $ i =0; $ i < NROFLOOPS; $ i++ ) { $query = " INSERT INTO Image ( image ) VALUES (' $image ')" ; $db−>query ( $query ) o r die ( $db−>e r r o r ) ; } } ?> Listing 5: insertMongoDb.php <?php r e q u i r e _ o n c e ( " generateData .php" ) ; // connect $m = new Mongo ( ) ; // select a database $db = $m−>t h e s i s ; 32 // select a collection $collection = $db−>Members ; $collectionImage = $db−>image ; $grid = $db−>getGridFS ( ) ; // Get parameters from commandline $ o p t i o n s = g e t o p t ( "t:n:" ) ; i f ( ! i s s e t ( $ o p t i o n s [ "n" ] ) | | ! i s s e t ( $ o p t i o n s [ "t" ] ) | | ! is_numeric ( $ o p t i o n s [ "n" ]) ) { die ( " ERROR : Optionsparameters is invalid !\n" ) ; } define ( " NROFLOOPS " , $ o p t i o n s [ "n" ] ) ; define ( "TYPE" , $ o p t i o n s [ "t" ] ) ; // Generate data and save to file i f (TYPE == "g" ) { i f ( f i l e _ e x i s t s ( FILE ) ) { u n l i n k ( FILE ) ; } $ h a n d l e = fopen ( FILE , 'w' ) o r die ( 'Cannot open file: ' . FILE ) ; f o r ( $ i =0; $ i < NROFLOOPS; $ i++ ) { $member = generate_member ( ) ; fwrite ( $handle , s e r i a l i z e ( $member ) . "\n" ) ; } fclose ( $handle ) ; } // Read from file and insert data to database e l s e i f (TYPE == "i" ) { i f ( ! f i l e _ e x i s t s ( FILE ) ) { die ( " ERROR : Please run setup first to create data file!" ) ; } $ h a n d l e = fopen ( FILE , "r" ) ; i f ( $handle ) { w h i l e ( ( $ b u f f e r = f g e t s ( $handle , 4 0 9 6 ) ) !== f a l s e ) { $ c o l l e c t i o n −>i n s e r t ( u n s e r i a l i z e ( $ b u f f e r ) ) ; } i f ( ! feof ( $handle ) ) { echo " Error : unexpected fgets () fail\n" ; } fclose ( $handle ) ; // Clear data file echo " Insert complete !" ; u n l i n k ( FILE ) ; } } // BatchInsert eq MultiQuery e l s e i f (TYPE == "im" ) { i f ( ! f i l e _ e x i s t s ( FILE ) ) { die ( " ERROR : Please run setup first to create data file!" ) ; 33 } } $ h a n d l e = fopen ( FILE , "r" ) ; $members = array ( ) ; i f ( $handle ) { w h i l e ( ( $ b u f f e r = f g e t s ( $handle , 4 0 9 6 ) ) !== f a l s e ) { array_push ( $members , u n s e r i a l i z e ( $ b u f f e r ) ) ; } i f ( ! feof ( $handle ) ) { echo " Error : unexpected fgets () fail\n" ; } fclose ( $handle ) ; // Insert all members $ c o l l e c t i o n −>b a t c h I n s e r t ( $members ) ; // Clear data file echo " batchInsert complete !" ; u n l i n k ( FILE ) ; } // Save image e l s e i f (TYPE == "img" ) { i f ( ! f i l e _ e x i s t s (IMAGE) ) { die ( " ERROR : Image not found !" ) ; } $ a r r = array ( ) ; $ r e f = &$ a r r ; $ a r r [ " image " ] = chunk_split ( base64_encode ( file_get_contents (IMAGE) ) ) ; f o r ( $ i =0; $ i < NROFLOOPS; $ i++ ) { $ s t a t u s = $ c o l l e c t i o n I m a g e −>i n s e r t ( $ r e f ) ; } } // Save image grid fs e l s e i f (TYPE == " fsimg " ) { i f ( ! f i l e _ e x i s t s (IMAGE) ) { die ( " ERROR : Image not found !" ) ; } // $image = chunk_split ( base64_encode ( file_get_contents ( IMAGE ))); $ f i l e N a m e = " Image " ; f o r ( $ i =0; $ i < NROFLOOPS; $ i++ ) { // Note metadata field & filename field $ s t o r e d f i l e = $ g r i d −>s t o r e F i l e (IMAGE, array ( " metadata " => array ( " filename " => $ f i l e N a m e ) , " filename " => $ f i l e N a m e ) ) ; } ?> } Listing 6: queryMysql.php 34 <?php r e q u i r e _ o n c e ( " generateData .php" ) ; define ( 'DB_HOST ' , 'localhost ' ) ; define ( 'DB_NAME ' , 'thesis ' ) ; define ( 'DB_USER ' , 'thesis ' ) ; define ( 'DB_PASSWORD ' , 'wip ' ) ; $db = new m y s q l i (DB_HOST,DB_USER,DB_PASSWORD,DB_NAME) ; i f ( $db−>c o n n e c t _ e r r n o ) { die ( " ERROR : Database Connection failed , Mysql Message : " . $ t h i s −>db−> connect_error ) ; } // Force Utf -8 communication $db−>s e t _ c h a r s e t ( 'utf8 ' ) ; // Get parameters from commandline $ o p t i o n s = g e t o p t ( "t:n:" ) ; i f ( ! i s s e t ( $ o p t i o n s [ "n" ] ) | | ! i s s e t ( $ o p t i o n s [ "t" ] ) | | ! is_numeric ( $ o p t i o n s [ "n" ]) ) { die ( " ERROR : Optionsparameters is invalid !\n" ) ; } define ( "TYPE" , $ o p t i o n s [ "t" ] ) ; define ( " NROFLOOPS " , $ o p t i o n s [ "n" ] ) ; i f (TYPE == "q" ) { $query = " SELECT Product . * , Category . * FROM ProductCategory INNER JOIN Product ON ProductCategory . productId = Product .id LEFT OUTER JOIN Category ON ProductCategory . categoryId = Category .id WHERE Category . title = '" .CATEGORY. "'" ; $db−>query ( $query ) o r die ( $db−>e r r o r ) ; } // Generate data e l s e i f (TYPE == "g" ) { // Insert all categories $categories = generate_categories () ; foreach ( $ c a t e g o r i e s a s $ c a t e g o r y ) { $query = " INSERT INTO Category ( title ) VALUES ('" . $ c a t e g o r y [ " title " ] . " ');" ; $db−>query ( $query ) o r die ( $db−>e r r o r ) ; } // Generate products f o r ( $ i =0; $ i < NROFLOOPS; $ i++ ) { $product = generate_product ( ) ; 35 $query = " INSERT INTO Product (title , description , quantity ) VALUES ('" . $ p r o d u c t [ " title " ] . "', '" . $ p r o d u c t [ " description " ] . "', '" . $ p r o d u c t [ " quantity " ] . " ');" ; $db−>query ( $query ) o r die ( $db−>e r r o r ) ; $ p r o d u c t I d = $db−>i n s e r t _ i d ; $categoryIds = generate_categories_ids () ; foreach ( $ c a t e g o r y I d s a s $ c a t e g o r y I d ) { $query = " INSERT INTO ProductCategory (productId , categoryId ) VALUES ('" . $ p r o d u c t I d . "', '" . $ c a t e g o r y I d . " ');" ; $db−>query ( $query ) o r die ( $db−>e r r o r ) ; } } } // Clear data e l s e i f (TYPE == "c" ) { $db−>query ( " TRUNCATE TABLE Product " ) o r die ( $db−>e r r o r ) ; $db−>query ( " TRUNCATE TABLE ProductCategory " ) o r die ( $db−>e r r o r ) ; $db−>query ( " TRUNCATE TABLE Category " ) o r die ( $db−>e r r o r ) ; } ?> Listing 7: queryMongoDb.php <?php r e q u i r e _ o n c e ( " generateData .php" ) ; // connect $m = new Mongo ( ) ; // select a database $db = $m−>t h e s i s ; // select a collection $ c o l l e c t i o n C a t e g o r y = $db−>Category ; $ c o l l e c t i o n P r o d u c t = $db−>Product ; // Get parameters from commandline $ o p t i o n s = g e t o p t ( "t:n:" ) ; i f ( ! i s s e t ( $ o p t i o n s [ "n" ] ) | | ! i s s e t ( $ o p t i o n s [ "t" ] ) | | ! is_numeric ( $ o p t i o n s [ "n" ]) ) { die ( " ERROR : Optionsparameters is invalid !\n" ) ; } define ( " NROFLOOPS " , $ o p t i o n s [ "n" ] ) ; define ( "TYPE" , $ o p t i o n s [ "t" ] ) ; 36 // Generate data with relations and insert into database i f (TYPE == "g" ) { $ i n s e r t e d C a t e g o r i e s = array ( ) ; $categories = generate_categories () ; foreach ( $ c a t e g o r i e s a s $ c a t ) { $ c o l l e c t i o n C a t e g o r y −>i n s e r t ( $ c a t ) ; array_push ( $ i n s e r t e d C a t e g o r i e s , $ c a t ) ; } f o r ( $ i =0; $ i < NROFLOOPS; $ i++ ) { $product = generate_product ( ) ; $productCategoryIds = generate_categories_ids () ; $productCategoryArray = array ( ) ; foreach ( $ p r o d u c t C a t e g o r y I d s a s $ c a t I d ) { $currentCat = $ i n s e r t e d C a t e g o r i e s [ $catId −1]; array_push ( $productCategoryArray , $ c u r r e n t C a t [ '_id ' ] ) ; } $ p r o d u c t [ 'productCategory ' ] = $productCategoryArray ; $ c o l l e c t i o n P r o d u c t −>i n s e r t ( $ p r o d u c t ) ; } } // Generate data for noqsl standard way and insert inte database i f (TYPE == "g2" ) { $ i n s e r t e d C a t e g o r i e s = array ( ) ; $categories = generate_categories () ; f o r ( $ i =0; $ i < NROFLOOPS; $ i++ ) { $product = generate_product ( ) ; $productCategoryIds = generate_categories_ids () ; $productCategoryArray = array ( ) ; foreach ( $ p r o d u c t C a t e g o r y I d s a s $ c a t I d ) { $currentCat = $ c a t e g o r i e s [ $catId −1]; array_push ( $productCategoryArray , $ c u r r e n t C a t [ 'title ' ] ) ; } $ p r o d u c t [ 'productCategory ' ] = $productCategoryArray ; $ c o l l e c t i o n P r o d u c t −>i n s e r t ( $ p r o d u c t ) ; } } // clear all data in database e l s e i f (TYPE == "c" ) { $ c o l l e c t i o n P r o d u c t −>remove ( ) ; $ c o l l e c t i o n C a t e g o r y −>remove ( ) ; } // query database relational e l s e i f (TYPE == "q" ) { $ c a t e g o r y O b j e c t = $ c o l l e c t i o n C a t e g o r y −>f i n d ( array ( 'title ' => CATEGORY) ) ; foreach ( $ c a t e g o r y O b j e c t a s $doc ) { $ c u r s o r = $ c o l l e c t i o n P r o d u c t −>f i n d ( array ( 'productCategory ' => $doc [ ' _id ' ] ) ) ; 37 } $resultArray = iterator_to_array ( $cursor ) ; } // query database not relational e l s e i f (TYPE == "q2" ) { $ c u r s o r = $ c o l l e c t i o n P r o d u c t −>f i n d ( array ( 'productCategory ' => CATEGORY) ) ; $resultArray = iterator_to_array ( $cursor ) ; } ?> 38 C C.1 Diagram Insättning av data Ubuntu 64 70 MySql MongoDb 60 Tid(s) 50 40 30 20 10 0 1000 10000 100000 10000000 Antal C.2 Insättning av data Ubuntu 32 45 MySql MongoDb 40 35 Tid(s) 30 25 20 15 10 5 0 1000 10000 100000 Antal 39 10000000 C.3 Filtrering av data Ubuntu 64 90 MySql MongoDb utan relationer MongoDb med relationer 80 70 Tid(s) 60 50 40 30 20 10 0 1000 10000 100000 10000000 40000000 Antal C.4 Filtrering av data Ubuntu 32 100 MySql MongoDb utan relationer MongoDb med relationer 90 80 70 Tid(s) 60 50 40 30 20 10 0 1000 10000 100000 10000000 Antal 40 40000000