Jedan od najbitnijih parametara za međusobnu usporedbu različitih vrsta baza podataka je brzina izvođenja upita. Zato smo za današnji tekst napravili jednostavan primjer mjerenja brzine za dva najpopularnija predstavnika u svojim kategorijama - MySQL (relacijske baze podataka) te MongoDB (noSQL baze podataka).
Ideja za organizaciju mjerenja brzine je u biti vrlo jednostavna. Istu vrstu i količinu podataka treba spremiti u obje baze podataka, te nakon toga napraviti mjerenje brzine rada na što sličnijim upitima. Naravno, tako jednostavno mjerenje ne može dati konačni odgovor o ukupnim performansama obaju sustava, jer bi za tako nešto trebalo pripremiti bitno složenije modele podataka, koristiti vrlo složene vrste upita i funkcija u njima i slično. Primjer ipak može poslužiti za dobivanje početnog dojma o tome je li jedna vrsta sustava u pogledu brzine bitno drugačija od druge vrste.
Slika 1. MySQL baza je pripremljena pomoću besplatnog alata dostupnog na adresi http://filldb.info/
Za pripremu MySQL baze za testiranje upotrijebljen je javno dostupan alat na web-adresi http://filldb.info/. Osim same strukture baze, pomoću navedenog alata moguće je prema zadanim pravilima pripremiti i željeni broj slogova u tablicama. Na samom kraju postupka bazu podataka moguće je izvesti u obliku standardnih SQL naredbi za korištenje na bilo kojem MySQL sustavu.
Test baza u ovom primjeru sastoji se od dviju tablica s podacima o autorima i njihovim objavama, međusobno povezanih odgovarajućom relacijom. Prva tablica sadrži 10.000 slogova, a druga 20.000 slogova.
Cjelokupna struktura baze podataka, zajedno s prvim slogom za svaku od tablica (da bi se stekao dojam o izgledu podataka), navedena je u nastavku.
CREATE TABLE IF NOT EXISTS `authors` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`first_name` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`last_name` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`email` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`birthdate` date NOT NULL,
`added` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `authors` (`id`, `first_name`, `last_name`, `email`, `birthdate`, `added`) VALUES
(1, 'Taylor', 'Kreiger', 'judah.jaskolski@example.com', '1993-07-27', '1988-07-17
...
CREATE TABLE IF NOT EXISTS `posts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`author_id` int(11) NOT NULL,
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`description` varchar(500) COLLATE utf8_unicode_ci NOT NULL,
`content` text COLLATE utf8_unicode_ci NOT NULL,
`date` date NOT NULL,
PRIMARY KEY (`id`),
KEY `author` (`author_id`),
CONSTRAINT `posts_ibfk_1` FOREIGN KEY (`author_id`) REFERENCES `authors` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=20001 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
INSERT INTO `posts` (`id`, `author_id`, `title`, `description`, `content`, `date`) VALUES
(1, 1, 'Accusamus hic consequatur similique aut impedit molestias ea.', 'Voluptatem est tenetur ut dolor dolores temporibus officiis. Quia fugit at qui enim voluptatem quibusdam aliquid sed. Minus quia at recusandae id corrupti.', 'Quo animi id officiis ut. Excepturi quisquam est est eveniet reprehenderit. Est doloribus impedit soluta quo impedit. A aliquam ad sint reiciendis.', '2002-03-18'),
…
Testna baza u MongoDB formatu pripremljena je prepisivanjem podataka iz MySQL formata pomoću odgovarajućeg programskog koda VB.NET, navedenog na kraju teksta. Kao rezultat njegovog izvođenja nastala je kolekcija od 20.000 dokumenata o objavama s uključenim podacima o autorima. Nakon prepisivanja podataka, na kolekciju dokumenata dodana su i dva indeksa kako bi se osigurala podrška u korištenju pomoću sličnih indeksa kakvi postoje u relacijskom modelu.
db.posts.createIndex( { pid: -1 } )
db.posts.createIndex( { author_id: -1 } )
Na kraju teksta naveden je programski kod za mjerenje brzine izvođenja upita u bazama podataka u oba formata. Mjerenje je izvedeno tako da su u obje opisane baze pomoću odgovarajućih petlji u 100 ponavljanja dodani novi podaci, koji su ažuriranni, a na kraju svakog ciklusa podaci su ponovo obrisani iz baze podataka. Kod relacijske baze korištene su transakcije kako bi se garantiralo izvođenje upita nad svim tablicama u transakciji, dok MongoDB garantira izvođenje operacije nad pojedinačnim dokumentom, bez posebne pripreme transakcije.
Slika 2. Testna baza u MySQL formatu može se na kraju postupka izvesti u obliku standardnih SQL naredbi
Slika 3. Isti podaci prepisani u MongoDB bazu kao kolekcija dokumenata.
Rezultati mjerenja prikazani su na sljedećoj slici u odgovarajućem sučelju VB.NET aplikacije. Za svaku vrstu baze podataka napravljeno je po pet mjerenja kako bi se dobili što stvarniji podaci koji uključuju i keširanje podataka te druge slične tehnike u oba modela.
Slika 4. Usporedno mjerenje brzine izvođenja istih operacija na dvije različite baze
Iz primjera je vidljivo da ne postoje bitne razlike u brzini izvođenja upita između baza podataka MySQL i MongoDB, bar kad je riječ o modelu podataka iz primjera.
Prepisivanje podataka između dvije baze:
Private Sub btnMySQL2MongoDB_Click(sender As Object, e As EventArgs) Handles btnMySQL2MongoDB.Click
Dim dbCN As New MySql.Data.MySqlClient.MySqlConnection(dbCS)
Dim SQLCommand As String = "select p.id, p.author_id, p.title, p.description, p.content, " &
"p.date, a.first_name, a.last_name, a.email, a.birthdate, " &
"a.added " &
"from posts p " &
"inner join authors a on p.author_id = a.id"
Dim i As Integer = 0
Dim client As New MongoClient()
Dim db = client.GetDatabase("testmongo")
Dim clist = db.GetCollection(Of Post)("posts")
Try
dbCN.Open()
Dim dbCMD As New MySql.Data.MySqlClient.MySqlCommand(SQLCommand, dbCN)
Dim dbDR As MySql.Data.MySqlClient.MySqlDataReader = dbCMD.ExecuteReader
While dbDR.Read()
Dim p As New Post
With p
.pid = dbDR.Item("id")
.author_id = dbDR.Item("author_id")
.title = dbDR.Item("title")
.description = dbDR.Item("description")
.content = dbDR.Item("content")
.datee = dbDR.Item("date")
.first_name = dbDR.Item("first_name")
.last_name = dbDR.Item("last_name")
.email = dbDR.Item("email")
.birthdate = dbDR.Item("birthdate")
.added = dbDR.Item("added")
End With
clist.InsertOne(p)
i += 1
If i Mod 100 = 0 Then
Me.Text = i.ToString : Application.DoEvents()
End If
End While
dbDR.Close()
Catch Ex As SystemException
MsgBox(Ex.Message)
Finally
If dbCN.State = ConnectionState.Open Then dbCN.Close()
dbCN.Dispose()
End Try
End Sub
Mjerenje brzine MySQL:
Private Sub btnTestMySQL_Click(sender As Object, e As EventArgs) Handles btnTestMySQL.Click
Dim tstart As DateTime = Now
Dim dbCN As New MySql.Data.MySqlClient.MySqlConnection(dbCS)
Try
dbCN.Open()
For i As Integer = 1 To 100
Dim SQLCommand As String = "INSERT INTO authors (id, first_name, last_name, email, birthdate, added) VALUES (10001, 'Nenad', 'Crnko', 'Nenad.Crnko@srce.hr', '1981-01-01', '2019-07-01 10:10:10'); "
SQLCommand += "INSERT INTO posts (id, author_id, title, description, content, date) VALUES (20001, 10001, 'Accusamus hic consequatur similique aut impedit molestias ea.', 'Voluptatem est tenetur ut dolor dolores temporibus officiis. Quia fugit at qui enim voluptatem quibusdam aliquid sed. Minus quia at recusandae id corrupti.', 'Quo animi id officiis ut. Excepturi quisquam est est eveniet reprehenderit. Est doloribus impedit soluta quo impedit. A aliquam ad sint reiciendis.', '2019-07-01'); "
SQLCommand += "update posts set date = '2019-07-02' where id = 20001; "
SQLCommand += "update posts set date = '2019-07-03' where author_id = 10001; "
SQLCommand = "delete from posts where id = 20001; "
SQLCommand += "delete from authors where id = 10001; "
Dim dbTransaction As MySql.Data.MySqlClient.MySqlTransaction
dbTransaction = dbCN.BeginTransaction(IsolationLevel.ReadCommitted)
Dim dbCMD As New MySql.Data.MySqlClient.MySqlCommand(SQLCommand, dbCN)
With dbCMD
.Connection = dbCN
.CommandType = CommandType.Text
.CommandTimeout = 30
.Transaction = dbTransaction
.CommandText = SQLCommand
.ExecuteNonQuery()
End With
dbTransaction.Commit()
SQLCommand = "delete from posts where id = 20001; "
SQLCommand = "delete from authors where id = 10001; "
dbTransaction = dbCN.BeginTransaction(IsolationLevel.ReadCommitted)
With dbCMD
.Connection = dbCN
.Transaction = dbTransaction
.CommandText = SQLCommand
.ExecuteNonQuery()
End With
dbTransaction.Commit()
Next
Catch Ex As SystemException
MsgBox(Ex.Message, MsgBoxStyle.Exclamation, "Upozorenje")
Finally
If dbCN.State = ConnectionState.Open Then dbCN.Close()
dbCN.Dispose()
End Try
Dim tend As DateTime = Now
Dim tdiff As TimeSpan = tend - tstart
lstDocuments.Items.Add("MySQL - vrijeme izvođenja: " + tdiff.TotalMilliseconds.ToString)
End Sub
Mjerenje brzine MongoDB:
Private Sub btnTestMongo_Click(sender As Object, e As EventArgs) Handles btnTestMongo.Click
Dim tstart As DateTime = Now
Dim client As New MongoClient()
Try
Dim db = client.GetDatabase("testmongo")
Dim clist = db.GetCollection(Of Post)("posts")
For i As Integer = 1 To 100
Dim p As New Post
With p
.pid = 20001
.author_id = 10001
.title = "accusamus hic consequatur similique aut impedit molestias ea."
.description = "voluptatem est tenetur ut dolor dolores temporibus officiis. quia fugit at qui enim voluptatem quibusdam aliquid sed. minus quia at recusandae id corrupti."
.content = "quo animi id officiis ut. excepturi quisquam est est eveniet reprehenderit. est doloribus impedit soluta quo impedit. a aliquam ad sint reiciendis."
.datee = "2019-07-01"
.first_name = "nenad"
.last_name = "crnko"
.email = "nenad.crnko@srce.hr"
.birthdate = "1981-01-01"
.added = "2019-07-01 10:10:10"
End With
clist.InsertOne(p)
Dim filter_update1 As BsonDocument = New BsonDocument("pid", "20001")
clist.UpdateOne(filter_update1, New BsonDocument("$set", New BsonDocument("datee", "2019-07-02")))
Dim filter_update2 As BsonDocument = New BsonDocument("author_id", "10001")
clist.UpdateOne(filter_update2, New BsonDocument("$set", New BsonDocument("datee", "2019-07-03")))
Dim filter_delete As BsonDocument = New BsonDocument("pid", "20001")
clist.DeleteOne(filter_delete)
Next
Catch Ex As SystemException
MsgBox(Ex.Message, MsgBoxStyle.Exclamation, "Upozorenje")
End Try
Dim tend As DateTime = Now
Dim tdiff As TimeSpan = tend - tstart
lstDocuments.Items.Add("MongoDB - vrijeme izvođenja: " + tdiff.TotalMilliseconds.ToString)
End Sub