Nio databaser på 2 GB, och den utan server vann.
Ett fungerande system, en datamängd, en kodväg, nio lagringsmotorer och en proxy. Var och en fick en maskin på 2 GB med applikationen boende på den. SQLite tog sex av åtta lässcenarier och delade förstaplatsen med PostgreSQL. Två motorer kom inte i mål.

De flesta databasjämförelser mäter något ingen kör: likformigt genererade rader, smickrande frågor, ett direkt drivrutinsanrop, en siffra med ett X efter.
En applikation pratar inte med en drivrutin. Den pratar genom ett datalager, en behörighetskontroll, ett filter för mjukraderade poster, en sidbrytningshjälpare och en serialiserare.
Så vi behöll allt det och bytte bara ut lagringsmotorn. Samma data, samma frågor, samma index, samma kodväg: SQLite, PostgreSQL, MongoDB, dpdb, MariaDB, MariaDB bakom MaxScale, ScyllaDB, Cassandra, CockroachDB och CouchDB. Nio scenarier, tio omgångar var.
Det nya är maskinen. En tidigare körning gav varje motor en egen server på 32 GB och PostgreSQL vann sju av nio. Den här ger var och en en låda på 2 GB med jämförelseprocessen boende på den — vilket är hur ett av våra system faktiskt driftsätts, och det ändrar svaret.
Vinnaren
Det är oavgjort, och de två motorer som delar förstaplatsen kunde knappast vara mer olika. SQLite och PostgreSQL har båda snittplaceringen 1,78 över de nio scenarierna.
De tar sig dit på olika vägar. SQLite vinner sex av de åtta lässcenarierna; PostgreSQL vinner de två andra och blir tvåa i sju av nio. Räknar man bara läsningar har SQLite 1,50 mot PostgreSQLs 1,75.
MongoDB är trea på 3,11 och äger skrivkolumnen helt med 23 900 rader per sekund, 91 % före nästa motor. Den vann inget lässcenario — samma resultat som på de stora maskinerna.
Marginalen i toppen är inte subtil. SQLite läser en rad på dess id på 9,67 ms där PostgreSQL tar 80,8: åtta gånger snabbare över 200 sekventiella uppslag, det bredaste glappet den här jämförelsen någonsin producerat mellan två fungerande motorer. Den tar sig dit genom att inte vara en server. Det finns ingen port, ingen socket, ingen tur och retur och ingen andra process som slåss om den enda kärnan.
- SQLite — snittplacering 1,78, sex scenariovinster, alla läsningar
- PostgreSQL — 1,78, två vinster (djup sida, exakt räkning), tvåa i sju av nio
- MongoDB — 3,11, en vinst (massinläggning, och det är inte jämnt)
- MariaDB — 5,44
- dpdb — 5,67
- ScyllaDB — 5,89
- CockroachDB — 6,11, ur de sju omgångar av tio den orkade slutföra
- Cassandra — 6,56
- CouchDB — 8,67, sist på varje läsning den besvarade, vägrade två den inte besvarade, och sexa på skrivningen
Krymp maskinen till 2 GB och motorn som slutar vara en server vinner sex av åtta läsningar.
Uppställningen
250 000 genererade poster per motor, i en egen databas, seedade från tomt. Sex identiska sekundärindex överallt, på plats medan raderna skrevs.
Varje motor fick en egen maskin: en vCPU, 2 GB, 50 GB disk, i samma datacenter. Varje låda skapades för sin motor, mättes, och förstördes så snart dess siffror var i säkerhet.
Jämförelseprocessen kördes PÅ den lådan, bredvid motorn, genom hela varje omgång. Det är premissen snarare än en kompromiss — applikationen och dess databas delar en maskin, så mätningen bör göra det också.
Varje motor hölls till samma 1 GB hur många processer den än fördelar dem över: MariaDBs buffertpool, ScyllaDBs Seastar-allokering, dpdbs heap, MaxScale bredvid den MariaDB den står framför. Det är utjämning, inte trimning.
Tio fulla omgångar var — töm, seeda om, kör om. Publicerade siffror poolar varje råmätning i stället för att medelvärdesbilda omgångarnas medianer: 100 iterationer per lässcell, 500 styckmätningar per skrivcell.
Innan någon tid rapporterades måste varje motor rymma exakt 250 000 rader och bära exakt den deklarerade indexuppsättningen, kontrollerat mot dess egen katalog i början av varje omgång.
Tre motorer tog sig inte igenom det helskinnade, och var och en behandlas där det hände i stället för att döljas: CockroachDB slutförde sju omgångar av tio, CouchDB slutförde tio och vägrade två scenarier i var och en av dem, och FerretDB slutförde aldrig en enda seedning.
Att skriva 250 000 rader
En fyllning från tomt, femtio stycken om femtusen, alla sex index redan på plats.
MongoDB 23 900 rader per sekund — 12,8 sekunder för hela fyllningen, och den enda kolumn den vinner.
ScyllaDB 3 380, vilket är 81 sekunder för samma arbete. Motorerna byggda för att sprida skrivningar över ett kluster betalar mest för att få en nod och en kärna.
CockroachDB är sist på 1 140 rader per sekund — 286 sekunder per fyllning, tjugotvå gånger MongoDBs, och skälet till att den bara slutförde sju omgångar. Raft-konsensus och en serialiserbar transaktion på varje insättning är inte gratis på en kärna.
Att läsa en rad på dess id
Tvåhundra sekventiella uppslag på primärnyckel. Scenariot som skiljer fältet mest åt, och det skiljer det med en faktor 125.
SQLite 9,67 ms mot PostgreSQLs 80,8. CouchDB är sist på 1 210 och dpdb näst sist på 428.
Båda ändarna har samma orsak. SQLite svarar inuti processen som frågade, så ett uppslag är ett funktionsanrop; dpdb svarar över HTTP till en andra process, så ett uppslag är ett anrop. Tvåhundra sekventiella turer är tvåhundra tillfällen att betala för det, och det är den enda form där skillnaden är hela mätningen. CouchDB, som talar HTTP av konstruktion, sitter i andra änden av samma axel.
Alla mätvärden för en besiktning
Ett indexerat uppslag på en främmande nyckel som returnerar 494 rader — den vanligaste frågan den här applikationen ställer.
SQLite 3,41 ms, PostgreSQL 7,97, MongoDB 11,2. Cassandra är sist av motorerna som svarade, på 22,1.
CouchDB besvarade den inte alls. I alla tio omgångarna kom frågan tillbaka från servern som en timeout — CouchDB som vägrar köra den snarare än kör den långsamt, vilket är beteendet den dokumenterar och det enda på den här sidan som inte är en siffra.
Här ligger sidans jämnaste avgörande: dpdb 18,3 ms mot MariaDB 18,8, ett glapp på 2,7 % mellan två motorer som kördes på två olika maskiner. Behandla det paret som oavgjort.
Första sidan
Femtio rader sorterade på datum, fallande. Det en användare ser när hen öppnar en lista.
SQLite 2,88 ms och PostgreSQL 3,85 är snabba nog att nätverket ut till webbläsaren kostar mer än frågan.
ScyllaDB 28,2, Cassandra 39,8 och CockroachDB 46,6: en godtycklig sortering är inte vad CQL är byggt för, oavsett maskinstorlek, och en distribuerad SQL-motor på en nod får ingen kompensation för maskineriet.
Det här är CouchDBs andra vägran. En Mango-sortering behöver ett index som täcker den, och i stället för att degradera avstår motorn.
Sida tvåhundra
Samma femtio rader, tiotusen ner. PostgreSQLs första vinst, och det tydligaste den gör bättre än SQLite.
PostgreSQL 4,99 ms, MongoDB 11,6, SQLite 17,4. En djup offset är där en riktig frågeplanerare och en riktig buffertpool tjänar in sitt minne. Det här och den exakta räkningen är de enda två läsningar SQLite inte vinner, och den förlorar båda mot samma två motorer.
ScyllaDB 249 ms och Cassandra 201. CQL har ingen OFFSET, så djup sidbrytning emuleras.
CouchDB tar 20,4 sekunder — fyratusen gånger PostgreSQL, och det bredaste enskilda glappet någonstans i den här jämförelsen.
Att filtrera på ett fält ingen indexerat
Tiotusen rader som matchar ett booleskt fält utan index på någon motor. Alla läser igenom, så det här mäter genomsökningshastighet och inget annat.
SQLite 75,1 ms, PostgreSQL 141. ScyllaDB 418 och MariaDB 405 — att söka igenom är det CQL är minst villigt att göra, och InnoDB är inte mycket gladare över det här.
CouchDB 4,7 sekunder, och dess p95 är 10,5: ungefär ett anrop av tjugo kostar mer än dubbelt det typiska, vilket är sidans bredaste svans.
Ett intervall inom en relation
Ett indexerat uppslag och en numerisk jämförelse tillsammans — frågan en rapport byggs av.
SQLite 2,03 ms, PostgreSQL 3,95, MongoDB 5,83. Sidans snabbaste siffror, på de minsta maskiner den här jämförelsen använt.
CockroachDB 23,5 och CouchDB 315 avslutar den.
Att räkna samlingen
Hur många rader finns det. Den enklaste frågan här, PostgreSQLs andra vinst, och den enda läsning där SQLite slås med klar marginal — 99 ms mot 437.
MongoDB 156 ms. MariaDB 1,75 sekunder, därför att InnoDB inte håller något exakt radantal och COUNT(*) läser igenom ett index för att få fram det — samma beteende den visade på en maskin med 32 GB, i samma multipel.
ScyllaDB och Cassandra kan inte besvara den som ett enda anrop alls, så deras siffra är en sidbruten genomsökning: 1,62 och 2,79 sekunder.
CouchDB 32,4 sekunder. Den håller en databas per samling, vilket borde göra en exakt räkning till en metadataläsning; på den här maskinen är den inte det.
Att läsa in allt
Alla 250 000 rader, genom applikationen, serialiserade.
SQLite 2,37 sekunder, PostgreSQL 3,02, ScyllaDB 3,72, CockroachDB 4,10. dpdb 7,64, och CouchDB 56,4 — tjugofyra gånger vinnaren.
ScyllaDB är värd en andra blick här: näst sist på den djupa sidan, tredje snabbast på att strömma hela samlingen, och den passerar MongoDB på vägen. Sekventiella massläsningar är åtkomstmönstret den byggdes kring, och det här är sidans enda scenario som ber om dem.
Vad en proxy kostar
MariaDB kördes två gånger: direkt, och genom MaxScale på samma maskin med samma rader och samma inloggning. Porten är den enda skillnaden, så varje glapp mellan de två kolumnerna är proxyn.
Det är ingen platt skatt, och den går inte ens åt ett håll. Punktläsningen — 200 sekventiella turer — kostar 31 % mer genom MaxScale. Allt som returnerar en bunt kommer tillbaka snabbare: relationsuppslaget med 28 %, det oindexerade filtret med 27 %, hela inläsningen av 250 000 rader med 28 %.
Den exakta räkningen och massinläggningen är identiska med den rapporterade siffran.
Den tidigare körningen mätte samma två riktningar på maskiner med 32 GB och en helt annan processor: 18,7 % långsammare på punktläsningen, 29 % snabbare på hela inläsningen. Att få tillbaka båda halvorna på en sextondel av minnet och en åttondel av kärnorna är ett starkare påstående än någondera körningen gör ensam.
Den troliga orsaken till vinsten på bunten är att proxyn frikopplar läsningen från motorn från skrivningen till klienten. Det är en hypotes; mätningen är det inte.
Motorerna som inte kom i mål
Två motorer besegrades av maskinen snarare än av varandra, och båda är värda mer än placeringen de hamnar på.
CockroachDB slutförde sju omgångar av tio. Två dog med att uppkopplingen bröts mitt i en seedning, och en hängde sig hela takgränsen på tre timmar utan att producera något alls. Dess kolumn är poolad ur de sju som överlevde, vilket smickrar den: omgångarna den förlorade är de där den hade problem.
FerretDB har ingen kolumn alls, och det är dess resultat snarare än en lucka i vårt.
Den slutförde aldrig en enda seedning på den här hårdvaran. Kärnans OOM-dödare tog den vid 783 MB med 50 100 av 250 000 rader skrivna, och den tog den igen vid varje uppdelning av minnesbudgeten vi försökte med.
Det som dödar den är formen på en översättande proxy: den svarar genom att materialisera en hel samling inuti processen som översätter, så dess minnesbehov följer datamängdens storlek snarare än sidans. På 32 GB är det osynligt och den slutförde varje scenario. På 2 GB är det fyndet.
Siffran som hade fått den att rymmas är skälet till att den inte har någon. Varje annan kolumn hålls till samma 1 GB, och en motor som mätts med mer är inte mätt mot dem.
CouchDB hör bara halvvägs hemma här. Den slutförde alla tio omgångarna och vägrade sedan två av de åtta lässcenarierna i var och en av dem — relationsuppslaget och första sidan, båda returnerade av servern som timeouts. De sex den besvarar, besvarar den sist.
Hur mycket av det här är mätfel
Nog för att spela roll i botten av tabellen och inte på långa vägar nog för att spela roll i toppen.
Varje motor kördes på en egen maskin. De är samma produkt i samma datacenter, men den här flottan registrerade ingen kalibrering mellan maskiner — flottan med 32 GB gjorde det, och fann en spridning på 4,2 % mellan nominellt identiska servrar. Anta något i den storleksordningen här och läs allt inom några procent som oavgjort.
Två avgöranden ligger innanför det: dpdbs relationsuppslag på 18,3 ms mot MariaDBs 18,8, och ScyllaDBs intervallsökning på 11,7 ms mot dpdbs 12,2. Ingetdera flyttar en placering ovanför femte.
Inget nära toppen är i fara. SQLites punktläsning är åtta gånger nästa motors och dess smalaste vinst är 34 %; ingen rimlig skillnad mellan två lådor av en produkt når någondera.
CockroachDBs kolumn bär ett andra slags fel de övriga inte har: 70 mätvärden per cell i stället för 100, hämtade ur omgångarna den överlevde. Det är en välvillig uppskattning av en motor som inte kom i mål, och den ska läsas som en.
Proxyjämförelsen är den enda på sidan utan någon maskin i sig alls — MaxScale och MariaDB är en server på en låda, och porten är hela skillnaden.
Varje anrop var sekventiellt och varje motor körde en nod. Inget här beskriver beteende under samtidighet eller över ett kluster, vilket är där ScyllaDB, Cassandra och CockroachDB är byggda för att löna sig — och en enkärnig låda är den minst representativa maskin som finns för någotdera.
Vad det här betyder om ni ska välja en
Rangordningen står ovan och den är verklig. Den är verklig för den här maskinen, vilket är poängen med att köra den på den här maskinen.
- En applikation, en liten låda, en process som läser — SQLite, och marginalen är inte jämn. Den vann sex av åtta läsningar genom att inte ha något nätverksprotokoll alls
- Samma egenskap är skälet att titta någon annanstans: SQLite har inget att erbjuda en andra applikationsserver, serialiserar sina skrivare, och dess övertag här ligger lika mycket i driftsättningen som i motorn
- Ad hoc-frågor, djup sidbrytning, exakta räkningar, åtkomstmönster som kommer att ändras efter lansering — PostgreSQL, som är tvåa nästan överallt och etta där en frågeplanerare spelar roll
- MongoDB är den snabbaste skrivaren med bred marginal och den bästa allroundmotorn efter de två, precis som på maskiner sexton gånger så stora
- Skrivtungt med åtkomstmönster kända i förväg — CQL-motorerna tjänar in sina begränsningar, men inte på en kärna: ScyllaDB skriver i en sjundedel av MongoDBs takt här
- MariaDB är konkurrenskraftig på skrivningar och på punktläsningen, och dess exakta räkning är 18 gånger PostgreSQLs
- En proxy framför en databas är ingen fast omkostnad och inte alltid en kostnad — mät den på ert eget åtkomstmönster
- En motor som svarar över HTTP betalar för varje tur och retur, så räkna era turer innan ni läser en punktläsningssiffra som en dom över dess lagring
- CockroachDBs skrivkostnad köper serialiserbara distribuerade transaktioner över noder; på en liten nod köper den ingenting och kostar tre omgångar av tio. Sätt den inte på en låda av den här storleken
- CouchDB är byggd kring förberäknade vyer, och ingen av de här frågorna är en. Den är sist på varje läsning den besvarade och vägrar de två mest ordinära en applikation ställer
Siffrorna
Varje siffra ovan är läst ur tabellen nedan i stället för inskriven i den här artikeln. Byt körning — flottan med 32 GB finns kvar — byt basmotor, jämför vilka två som helst.
Anger MongoDB mot PostgreSQL, medianvärden. Att smalna av grupperna tonar ned rader som faller utanför — ingenting tas bort från sidan.
Körning H — en maskin på 2 GB per motor, med applikationen på den också
Drop-in-jämförelseMot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Referensmotor — varje faktor på sidan anges mot den. Dess egen sammanräkning ovan står mot den snabbaste av de andra motorerna i vart och ett av 9 scenarier, medianvärden.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 7 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
| Scenario | Rader | SQLite | Postgres | MongoDB | dpdb | MariaDB | MaxScale | ScyllaDB | Cassandra | Cockroach | CouchDB | Faktor | Relativt | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Median | p95 | Median | p95 | Median | p95 | Median | p95 | Median | p95 | Median | p95 | Median | p95 | Median | p95 | Median | p95 | Median | p95 | ||||
Massinläggning, 250 000 posterSkrivgenomströmning med sex sekundärindex redan på plats. Skrivningar | 250 000 | 10 400 rows/s | 7 490 rows/s | 12 500 rows/s | 10 900 rows/s | 23 900 rows/s | 10 500 rows/s | 6 860 rows/s | 2 730 rows/s | 11 700 rows/s | 9 890 rows/s | 11 700 rows/s | 10 300 rows/s | 3 380 rows/s | 2 280 rows/s | 4 920 rows/s | 2 450 rows/s | 1 140 rows/s | 462 rows/s | 5 930 rows/s | 5 200 rows/s | MongoDB 1.91× | |
Punktläsning på identifierare, 200 anrop200 uppslag på primärnyckel i följd, ett tur och retur vardera. Nyckelåtkomst | 200 | 9.7 ms | 33 ms | 81 ms | 109 ms | 129 ms | 205 ms | 428 ms | 572 ms | 88 ms | 135 ms | 116 ms | 166 ms | 240 ms | 309 ms | 125 ms | 246 ms | 218 ms | 434 ms | 1.21 s | 1.76 s | Postgres 1.6× | |
Alla mätvärden för en besiktningVarje underordnad post till en förälder, på en indexerad främmande nyckel. Nyckelåtkomst | 494 | 3.4 ms | 6.3 ms | 8.0 ms | 10 ms | 11 ms | 15 ms | 18 ms | 25 ms | 19 ms | 33 ms | 14 ms | 29 ms | 16 ms | 20 ms | 22 ms | 78 ms | 17 ms | 52 ms | — | — | Postgres 1.41× | |
Första sorterade sidan, 50 raderSida ett av en besiktnings mätvärden, sorterade på mätdatum med det senaste först. Sidindelning | 50 | 2.9 ms | 3.9 ms | 3.9 ms | 5.0 ms | 7.2 ms | 10 ms | 31 ms | 75 ms | 22 ms | 25 ms | 21 ms | 26 ms | 28 ms | 36 ms | 40 ms | 113 ms | 47 ms | 143 ms | — | — | Postgres 1.86× | |
Djup sida, sida 200Hoppa över 9 950 rader och returnera de 50 följande. Det en numrerad bläddrare ber om. Sidindelning | 50 | 17 ms | 21 ms | 5.0 ms | 6.2 ms | 12 ms | 24 ms | 59 ms | 115 ms | 72 ms | 78 ms | 71 ms | 84 ms | 249 ms | 326 ms | 201 ms | 378 ms | 85 ms | 164 ms | 20.4 s | 21.3 s | Postgres 2.32× | |
Filtrerad genomsökning på ett oindexerat booleskt fältVarje post där en godkännandeflagga är falsk. Indexerat på ingen av dem. Genomsökningar och filter | 10 000 | 75 ms | 87 ms | 141 ms | 192 ms | 221 ms | 246 ms | 244 ms | 325 ms | 405 ms | 457 ms | 296 ms | 353 ms | 418 ms | 495 ms | 347 ms | 538 ms | 315 ms | 1.08 s | 4.70 s | 10.5 s | Postgres 1.57× | |
Intervallsökning på ett oindexerat talEn indexerad likhet plus ett större-än på ett oindexerat mätvärde. Genomsökningar och filter | 165 | 2.0 ms | 2.9 ms | 4.0 ms | 5.0 ms | 5.8 ms | 7.4 ms | 12 ms | 21 ms | 14 ms | 17 ms | 13 ms | 15 ms | 12 ms | 15 ms | 18 ms | 57 ms | 24 ms | 102 ms | 315 ms | 367 ms | Postgres 1.48× | |
Exakt räkning av hela samlingenHur många poster finns det. Inte en uppskattning. Arbete över hela samlingen | 250 000 | 437 ms | 478 ms | 99 ms | 171 ms | 156 ms | 171 ms | 1.42 s | 1.56 s | 1.75 s | 1.86 s | 1.75 s | 1.80 s | 1.62 s | 1.79 s | 2.79 s | 3.17 s | 1.14 s | 3.02 s | 32.4 s | 33.3 s | Postgres 1.58× | |
Läs in hela samlingenVarje post, deserialiserad in i applikationen. Arbete över hela samlingen | 250 000 | 2.37 s | 2.49 s | 3.02 s | 3.78 s | 6.10 s | 6.43 s | 7.64 s | 10.9 s | 6.68 s | 6.98 s | 4.80 s | 4.96 s | 3.72 s | 3.94 s | 4.60 s | 5.00 s | 4.10 s | 8.02 s | 56.4 s | 57.5 s | Postgres 2.02× | |
Metod
- En motor per maskin. En STARTER-1xCPU-2GB i se-sto1 per motor — 1 vCPU, 2 GB, 50 GB disk — skapad för sin motor, mätt, och riven så snart resultaten var av den
- Mätprocessen kör PÅ maskinen, bredvid motorn, under hela varje runda. Det är premissen snarare än en kompromiss: ett dp-system driftsätter applikationen och dess databas på en maskin, och det är den maskinen som mäts här
- Varje motor hölls till samma 1 GB, hur många processer den än fördelar det på — MariaDB:s InnoDB-pool, ScyllaDB:s Seastar-tilldelning, dpdb:s --ram-mb, MaxScale bredvid den MariaDB den står framför, FerretDB tillsammans med sin underliggande PostgreSQL. Taket är utjämning snarare än trimning: en motor vars förvalda cache är ett fast litet tal vore annars den enda som inte kunde nå maskinen
- Tio fullständiga rundor per motor. Varje runda river indexuppsättningen, tömmer, sår om 250 000 rader från tomt och kör om varje scenario, så skrivkolumnen är tio oberoende fyllningar och läskolumnerna tio oberoende processer
- Publicerade siffror slår samman RÅVÄRDENA från alla tio rundorna — 100 iterationer per läscell, 500 klumptider per skrivcell — och redovisar en median och en p95 över hela mängden. Inte ett medelvärde av tio medianer, vilket är medianen av ingenting och dras just av de avvikare en median står emot
- 10 iterationer per runda och scenario, 2 uppvärmningar förkastade, 200 punktläsningar i följd per iteration
- Varje LÄSNING går genom applikationens datatjänst, frågehanterare, adapterladdare och datalager — aldrig genom drivrutinen
- Skrivkolumnen går in ett steg lägre. Såmaskinen anropar motoradapterns create_many direkt, så massinläggningen är adapter plus motor utan datatjänsten ovanför — dp-kod i båda fallen och samma djup i varje motor, men inte samma djup som läskolumnerna
- Skrivningarna mättes som en fyllning från tomt med de sex paritetsindexen redan på plats, i 50 klumpar om 5 000 rader per runda
- En runda som inte gav några mätvärden är en MISSLYCKAD runda, kontrollerad snarare än förutsatt. Varje steg i en runda kan avsluta med 0 utan att ha mätt något, och en tidigare flotta redovisade åttio sådana rundor som insamlade innan någon öppnade en resultatfil
- Radantalen kontrollerades EXAKT före varje tidtagning. En motor som håller 250 001 rader svarar på en annan fråga än en som håller 250 000, och ingen tid den producerar skulle visa det
- Motorversionerna hämtades ur varje servers eget gränssnitt i stället för att skrivas ned: MongoDB 8.0.29, PostgreSQL 17.11, MariaDB 11.4.12, MaxScale 23.08 readwritesplit, ScyllaDB 6.2.3, Cassandra 5.0.9, SQLite 3.53.3, dpdb byggd från 0531553347dc, CockroachDB v24.3.5, CouchDB 3.4.3
- Ett tak på 120 sekunder per iteration — en motor som överskrider det bokförs som en tidsgräns i stället för att lämnas tom
Indexparitet
- Varje motor: sekundärindex på _type, _besiktning_id, _system_id, _ventil_id, _room_id och _anmarkning_id
- IndexUPPSÄTTNINGEN kommer ur en enda deklaration i kodbasen, läst av varje adapter, så ingen motor kan glida ifrån en annan
- Närvarande i varje motor medan raderna skrevs, inte tillagda efteråt, i var och en av de tio rundorna
- Verifierat ur varje motors egen katalog omedelbart före den första mätningen i varje runda, på varje maskin oberoende. Körningen vägrar redovisa en siffra när en motor bär ett index som paritetsuppsättningen inte deklarerar
- SQLite indexerar ett UTTRYCK direkt — json_extract(doc, '$.field') — utan genererad kolumn och utan schemaändring. Det är den enda motorn här för vilken paritetsuppsättningen inte kostar något strukturellt
- MariaDB kan inte indexera ett uttryck alls, så dess sex är index på GENERERADE kolumner som håller extraktionen
- dpdb härleder indexnamn på serversidan ur de fält de täcker, så det är den enda motorn vars paritetsuppsättning inte går att matcha på NAMN. Den verifieras på FÄLT i stället — en skillnad kontrollen fick lära sig, efter att tidigare ha redovisat en motor med exakt de sex rätta indexen som helt utan
Vad körningen inte visar
- CockroachDB fullbordade SJU av sina tio rundor och dess kolumn är sammanslagen ur de sju — 70 stickprov per läscell där varje annan kolumn har 100. Läs den som en fördelaktig uppskattning snarare än som en jämförbar siffra: de tre förlorade rundorna är de där motorn hade det svårt, så det som överlevde är dess goda beteende. Runda 7 och runda 10 dog båda med klienten rapporterande en avbruten anslutning mitt i insådden, och runda 8 hängde sig hela tretimmarstaket utan att producera något. Tio rundor försöktes på den här motorn precis som på de andra.
- CouchDB VÄGRADE två av de åtta lässcenarierna i alla tio rundorna. Besiktningsuppslaget och första sidan kom båda tillbaka från POST /_find som en tidsgräns på serversidan — CouchDB som avböjer att köra frågan i stället för att köra den långsamt — och de två cellerna bär vägran i stället för en siffra. Dess övriga sex är tio fullständiga rundor och är direkt jämförbara.
- FerretDB är en VÄGRAN, inte en tidsgräns och inte en lucka. Den fullbordade aldrig en insådd på den här hårdvaran: kärnans oom-killer tog den vid 783 MB med 50 100 av 250 000 rader skrivna, vid varje minnesfördelning som prövades, och att ge den vad den ville ha hade betytt att överskrida den gigabyte varje annan kolumn hålls till. Siffran som hade fått den att rymmas är skälet till att den inte finns.
- Den här körningen och körning G svarar på OLIKA FRÅGOR och ingen ersätter den andra. Körning G mäter en databas med en maskin på 32 GB för sig själv; den här mäter en databas som delar 2 GB med applikationen. Lästa mot varandra säger de hur mycket av en motors ställning som är dess egen och hur mycket som var hårdvaran — vilket är det mest användbara någon av dem säger.
- SQLites vinst är en vinst vid DEN HÄR formen och generaliserar inte förbi den. Varje anrop här är sekventiellt och i en process; SQLite serialiserar skrivare, har inget nätverksprotokoll att multiplexa, och den fördel av att köra i processen som gör dess punktläsning åtta gånger snabbare är samma egenskap som ger den ingenting att erbjuda en andra applikationsserver. Scenariolistan är vad den vann, inte driftsformen.
- Varje anrop var sekventiellt. Ingenting här säger något om beteende under samtidighet, vilket är där ScyllaDB, Cassandra och CockroachDB är byggda för att löna sig — och det är den axel där en maskin med 1 vCPU är minst representativ för någonting.
- En nod var. Det här är siffror för en nod från motorer vars hela designpremiss är fler än en nod, på en maskin mindre än vad flera av dem anger som ett minimum.
- Skrivkolumnen är en fyllning från TOMT. Bara körningar som mäter samma form kan läsas mot varandra.
- MaxScale är en PROXY, inte en lagringsmotor, och dess kolumn är bara meningsfull läst mot MariaDB:s. De två är samma server på samma maskin och skiljer sig i porten, så varje avstånd mellan de kolumnerna är proxyn. Att läsa MaxScale mot PostgreSQL jämför en proxad motor med en direkt och svarar på ingenting.
- Proxyn är ingen platt skatt, och det är fyndet snarare än ett förbehåll. Punktläsningen — 200 tur och retur i följd — kostar 31 % mer genom MaxScale. load_all, ett anrop som returnerar 250 000 rader, kommer tillbaka 28 % SNABBARE, och den filtrerade genomsökningen 27 % snabbare. Körning G mätte samma två riktningar på maskiner med 32 GB och en helt annan processor, vilket är ett starkare påstående än någon av körningarna gör ensam.
- MaxScale konfigurerades med enable_root_user, eftersom den direkta körningen ansluter som root och paret måste skilja sig åt enbart i porten. Det är ett mätbeslut, inte en rekommendation för drift.
- Djup sida och filtrerad genomsökning är fönster över en OSORTERAD mängd — ingen sortering begärs, så vilka rader som kommer tillbaka är motorns egen naturliga ordning. Varje motor returnerade samma ANTAL i båda; radmängderna skiljer sig legitimt.
- ScyllaDB och Cassandra kan fortfarande inte betjäna COUNT(*) över 250 000 rader som ett enda anrop, så deras räkning är en sidindelad genomsökning. Det är adaptern som gör vad en produktionsimplementation måste göra.
- Tre brister i dp:s egna adaptrar hittades av den här körningen snarare än av applikationen, och alla tre är rättelser i raderingsvägen som en mätning belastar hårdare än något annat: MariaDB matchade ingenting på ett booleskt filter, CouchDB avbröt en massradering på en rad som redan var borta, och dpdb återvände från en med en tiondel av raderna kvar. De två första är rättade; den tredje är en känd brist som flottan går runt. Ingen av dem påverkar en siffra nedan — de bröt rundor i stället för att snedvrida dem, vilket är det felläge att föredra.
- Körning G och körningarna på den bärbara datorn före den står kvar på sidan och deras siffror är inte felaktiga. De är korrekta mätningar av andra maskiner.
Körning G — en maskin per motor, tio rundor sammanslagna
Drop-in-jämförelseMot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Referensmotor — varje faktor på sidan anges mot den. Dess egen sammanräkning ovan står mot den snabbaste av de andra motorerna i vart och ett av 9 scenarier, medianvärden.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 8 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
| Scenario | Rader | MongoDB | Postgres | Cockroach | ScyllaDB | Cassandra | CouchDB | FerretDB | MariaDB | MaxScale | Faktor | Relativt | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Median | p95 | Median | p95 | Median | p95 | Median | p95 | Median | p95 | Median | p95 | Median | p95 | Median | p95 | Median | p95 | ||||
Massinläggning, 250 000 posterSkrivgenomströmning med sex sekundärindex redan på plats. Skrivningar | 250 000 | 31 800 rows/s | 28 000 rows/s | 14 400 rows/s | 13 500 rows/s | 2 610 rows/s | 1 850 rows/s | 17 900 rows/s | 15 900 rows/s | 28 300 rows/s | 17 100 rows/s | 10 600 rows/s | 10 100 rows/s | 6 170 rows/s | 5 850 rows/s | 12 600 rows/s | 11 400 rows/s | 12 400 rows/s | 11 200 rows/s | MongoDB 2.21× | |
Punktläsning på identifierare, 200 anrop200 uppslag på primärnyckel i följd, ett tur och retur vardera. Nyckelåtkomst | 200 | 100 ms | 125 ms | 69 ms | 76 ms | 228 ms | 285 ms | 62 ms | 90 ms | 80 ms | 105 ms | 679 ms | 705 ms | — | — | 60 ms | 78 ms | 72 ms | 89 ms | Postgres 1.44× | |
Alla mätvärden för en besiktningVarje underordnad post till en förälder, på en indexerad främmande nyckel. Nyckelåtkomst | 494 | 8.3 ms | 9.1 ms | 3.4 ms | 4.7 ms | 50 ms | 67 ms | 7.1 ms | 7.8 ms | 12 ms | 19 ms | 130 ms | 161 ms | 33.8 s | 35.8 s | 8.8 ms | 14 ms | 9.2 ms | 13 ms | Postgres 2.43× | |
Första sorterade sidan, 50 raderSida ett av en besiktnings mätvärden, sorterade på mätdatum med det senaste först. Sidindelning | 50 | 3.3 ms | 3.6 ms | 2.1 ms | 2.4 ms | 60 ms | 82 ms | 13 ms | 17 ms | 21 ms | 27 ms | 243 ms | 1.57 s | 40.2 s | 42.2 s | 13 ms | 18 ms | 13 ms | 14 ms | Postgres 1.52× | |
Djup sida, sida 200Hoppa över 9 950 rader och returnera de 50 följande. Det en numrerad bläddrare ber om. Sidindelning | 50 | 11 ms | 11 ms | 4.2 ms | 4.3 ms | 29 ms | 37 ms | 269 ms | 287 ms | 138 ms | 148 ms | 3.46 s | 3.64 s | 4.23 s | 4.35 s | 74 ms | 75 ms | 73 ms | 74 ms | Postgres 2.6× | |
Filtrerad genomsökning på ett oindexerat booleskt fältVarje post där en godkännandeflagga är falsk. Indexerat på ingen av dem. Genomsökningar och filter | 10 000 | 151 ms | 163 ms | 51 ms | 61 ms | 101 ms | 123 ms | 393 ms | 404 ms | 262 ms | 271 ms | 1.34 s | 7.47 s | 3.60 s | 3.69 s | 156 ms | 165 ms | 146 ms | 154 ms | Postgres 2.94× | |
Intervallsökning på ett oindexerat talEn indexerad likhet plus ett större-än på ett oindexerat mätvärde. Genomsökningar och filter | 165 | 4.4 ms | 4.9 ms | 2.1 ms | 3.4 ms | 49 ms | 65 ms | 6.3 ms | 6.7 ms | 11 ms | 11 ms | 115 ms | 124 ms | 33.7 s | 34.6 s | 9.9 ms | 10 ms | 10 ms | 11 ms | Postgres 2.1× | |
Exakt räkning av hela samlingenHur många poster finns det. Inte en uppskattning. Arbete över hela samlingen | 250 000 | 157 ms | 161 ms | 38 ms | 39 ms | 524 ms | 576 ms | 2.76 s | 2.84 s | 2.26 s | 2.36 s | 14.7 s | 15.2 s | 30.3 s | 31.8 s | 1.81 s | 1.82 s | 1.81 s | 1.82 s | Postgres 4.12× | |
Läs in hela samlingenVarje post, deserialiserad in i applikationen. Arbete över hela samlingen | 250 000 | 3.46 s | 3.52 s | 1.11 s | 1.18 s | 1.49 s | 1.55 s | 5.26 s | 5.38 s | 3.32 s | 3.39 s | 19.3 s | 19.9 s | 55.7 s | 57.3 s | 3.81 s | 3.87 s | 2.71 s | 2.81 s | Postgres 3.12× | |
Metod
- En motor per maskin. Sju m5d.2xlarge i eu-north-1a, 8 vCPU, 32 GB och en lokal NVMe var, en motor installerad per maskin och ingenting annat på den
- Ingen minnesgräns, ingen processorgräns, ingen granne. Varje motor hade hela maskinen, vilket är den miljö en databas faktiskt driftsätts i och motsatsen till körning F
- Tio fullständiga rundor per motor. Varje runda river motorn, sår om 250 000 rader och kör om varje scenario, så skrivkolumnen är tio oberoende fyllningar och läskolumnerna tio oberoende processer
- Ingen rotation av motorerna, eftersom det inte finns någon ordning att rotera. Körning F roterade för att upphäva effekten av att sju motorer delade en disk; en maskin per motor tar bort effekten i stället för att korrigera för den
- Publicerade siffror slår samman råvärdena från alla tio rundorna, 100 iterationer per läscell och 500 klumptider per skrivcell, och redovisar en median och en p95 över hela mängden
- Ett scenario som gick över tidsgränsen bidrar med inga stickprov och står obesvarat. FerretDB:s punktläsning gick över tidsgränsen i alla tio rundorna och publiceras som en tidsgräns, inte som en lucka
- 10 iterationer per runda och scenario, 2 uppvärmningar förkastade, 200 punktläsningar i följd per iteration
- Varje LÄSNING går genom applikationens datatjänst, frågehanterare, adapterladdare och datalager — aldrig genom drivrutinen
- Skrivkolumnen går in ett steg lägre. Såmaskinen anropar motoradapterns create_many direkt, så massinläggningen är adapter plus motor utan datatjänsten ovanför — dp-kod i båda fallen och samma djup i varje motor, men inte samma djup som läskolumnerna
- Radernas IDENTITET jämfördes MELLAN MASKINER. Varje maskin sammanfattade _id-mängden för varje scenario den körde och skrev den till disk; de sju sammanfattningsfilerna jämfördes efteråt och krävdes stämma överens. Motorer som aldrig samexisterar måste ändå returnera samma rader
- Indexpariteten kontrollerades vid mättillfället på varje maskin och i varje runda, och körningen vägrar redovisa en siffra när en motor bär ett index som paritetsuppsättningen inte deklarerar
- Skrivningarna mättes som en fyllning från tomt med de sex paritetsindexen redan på plats, i 50 klumpar om 5 000 rader per runda
- Varje maskin kalibrerades före och efter sina rundor — ett sha256-pass på en kärna och en disksond med direkt-IO — så att en långsam maskin syns som en långsam maskin i stället för som en långsam motor
- Motorversionerna hämtades ur varje servers eget gränssnitt: MongoDB 8.0.28, PostgreSQL 17.10, CockroachDB v24.3.5, ScyllaDB 6.2.3, Cassandra 5.0.8, CouchDB 3.4.3, FerretDB v1.24.0, MariaDB 11.4.12, MaxScale 23.08.13
- MariaDB och MaxScale kördes på en NIONDE maskin av samma typ, efter varandra i stället för samtidigt, så att var och en ändå hade maskinen för sig själv medan den mättes. Samma verktyg, samma tio rundor, samma 250 000 rader, samma paritetsuppsättning
- Proxyparet skiljer sig åt i PORTEN och ingenting annat — samma server, samma adapter, samma inloggning, samma datamängd. 3306 direkt, 4006 genom MaxScales readwritesplit-lyssnare
- Ett tak på 120 sekunder per iteration — en motor som överskrider det bokförs som en tidsgräns i stället för att lämnas tom
Indexparitet
- Alla nio motorerna: sekundärindex på _type, _besiktning_id, _system_id, _ventil_id, _room_id och _anmarkning_id
- IndexUPPSÄTTNINGEN kommer ur en enda deklaration i kodbasen, läst av varje adapter, så ingen motor kan glida ifrån en annan
- Närvarande i varje motor medan raderna skrevs, inte tillagda efteråt, i var och en av de tio rundorna
- Verifierat ur varje motors egen katalog omedelbart före den första mätningen i varje runda, på var och en av de sju maskinerna oberoende
- FerretDB:s sex paritetsindex skapades, bekräftades och konstaterades finnas som b-träd i dess egen underliggande PostgreSQL — och användes aldrig en enda gång. Dess punktläsning är en fullständig genomsökning av samlingen per uppslag, och det är därför den går över tidsgränsen
- MariaDB kan inte indexera ett uttryck alls, så dess sex är index på GENERERADE kolumner som håller extraktionen. Det gör frågans formulering avgörande snarare än kosmetisk: EXPLAIN på den sådda tabellen ger type=ref, key=dpx__besiktning_id, 4 rader när kolumnen refereras, och type=ALL utan nyckel när samma filter skrivs som den inbäddade extraktionen. MariaDB skriver inte om det ena till det andra så som MySQL 8 gör
Vad körningen inte visar
- Maskinerna var inte identiska. Turboklockan låg mellan 3105 och 3215 MHz och sha256-kalibreringen på en kärna mellan 1310 och 1365 ms, en spridning på 4,2 %; diskarna gick inte att skilja åt vid 138–140 MB/s skrivning och 131 MB/s läsning. Per maskin: FerretDB 1310, CouchDB 1314, Cassandra 1315, ScyllaDB 1333, MongoDB 1353, PostgreSQL 1353, MariaDB 1353, CockroachDB 1365.
- Den knappaste placeringen på sidan är MariaDB:s punktläsning på 60,4 ms mot ScyllaDB:s 62,2, en marginal på 3,0 %. Den överlever korrigering och mer därtill: MariaDB:s maskin kalibrerar 1,5 % LÅNGSAMMARE, så en normalisering flyttar den till 59,5 ms och vidgar avståndet till 4,5 %. Det är ändå den enda siffran här där spridningen mellan rundorna är värd att läsa bredvid medianen — MariaDB låg mellan 55,1 och 72,7 ms över sina tio rundor mot ScyllaDB:s 59,3 till 64,6, och vann åtta av tio och förlorade två rejält.
- Varje motor kördes i Docker med en publicerad port, så varje tur och retur korsade ett veth-par och en DNAT i kärnan — ungefär 20–50 mikrosekunder. Värdnätverk hade tagit bort det gratis och användes inte. Det är en konstant per scenario, identisk för varje motor, så det pressar ihop avstånden något och kan inte kasta om någon ordning; punktläsningen med sina 200 anrop bär mest av det.
- Containrar snarare än installationer direkt på värden, med avsikt. Sju installationer på värden betyder sju olika konfigurationsytor — bara ScyllaDB:s uppsättningsskript ställer om IO-schemaläggaren och hugepages — och leverantörernas avbildningar är det närmaste lika behandling som finns.
- Varje anrop var sekventiellt. Ingenting här säger något om beteende under samtidighet, vilket är där ScyllaDB, Cassandra och CockroachDB är byggda för att löna sig.
- En nod var. Det här är siffror för en nod från motorer vars hela designpremiss är fler än en nod.
- Skrivkolumnen är en fyllning från TOMT. Bara körningar som mäter samma form kan läsas mot varandra.
- Djup sida och filtrerad genomsökning är fönster över en OSORTERAD mängd — ingen sortering begärs, så vilka rader som kommer tillbaka är motorns egen naturliga ordning. Alla sju returnerade samma ANTAL i båda; radmängderna skiljer sig legitimt, och verifieringen mellan maskinerna namnger dem i stället för att dölja dem.
- ScyllaDB och Cassandra kunde fortfarande inte betjäna COUNT(*) över 250 000 rader som ett enda anrop, så deras räkning är en sidindelad genomsökning. Det är adaptern som gör vad en produktionsimplementation måste göra.
- CouchDB blev snabbare nästan överallt när taket togs bort — dess punktläsning gick från 2 970 ms till 679 ms — och tre gånger LÅNGSAMMARE på den djupa sidan, 1 090 ms till 3 460 ms. Att få mer minne är inte enbart goda nyheter för den.
- MaxScale är en PROXY, inte en lagringsmotor, och dess kolumn är bara meningsfull läst mot MariaDB:s. De två är samma server på samma maskin och skiljer sig i porten — så varje avstånd mellan de kolumnerna är proxyn. Att läsa MaxScale mot PostgreSQL eller MongoDB jämför en proxad motor med en direkt och svarar på ingenting.
- Proxyn är ingen platt skatt, och det är fyndet snarare än ett förbehåll. Punktläsningen — 200 tur och retur i följd — kostar 18,7 % mer genom MaxScale. load_all — ett anrop som returnerar 250 000 rader — kommer tillbaka 29 % SNABBARE, 3 811 ms direkt mot 2 706 ms proxat, och de tio rundorna på var sida överlappar inte alls. Den troligaste förklaringen är att proxyn kopplar isär serverns läsning från klientens tolkning så att de två överlappar, men det är en hypotes om en mekanism vi inte instrumenterade, och mätningen står utan den.
- MaxScale konfigurerades med enable_root_user, eftersom den direkta körningen ansluter som root och paret måste skilja sig åt enbart i porten. Det är ett mätbeslut, inte en rekommendation för drift.
- MariaDB:s buffertpool sattes till 24G i stället för att lämnas på sin förvalda 128 MB. InnoDB öppnar sina datafiler med O_DIRECT — bekräftat på maskinen — så operativsystemets sidcache backar den inte, och förvalet hade i praktiken varit hela dess cache medan varje annan motor här når större delen av maskinen. Det är utjämning för att matcha de andra, inte trimning förbi dem: ingen dimensionering av redo-loggen, ingen trimning av utskrivningen, ingen trådpool.
- Körning F står kvar på sidan och dess siffror är inte felaktiga. De är korrekta mätningar av sju motorer som delade en bärbar dator, en av dem med sina data inuti en annan, tagna fem gånger.
Körning F — en indexuppsättning, inga extraindex från adaptern, fem rundor sammanslagna
Drop-in-jämförelseMot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Referensmotor — varje faktor på sidan anges mot den. Dess egen sammanräkning ovan står mot den snabbaste av de andra motorerna i vart och ett av 9 scenarier, medianvärden.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 8 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
| Scenario | Rader | MongoDB | Postgres | Cockroach | ScyllaDB | Cassandra | CouchDB | FerretDB | Faktor | Relativt | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Median | p95 | Median | p95 | Median | p95 | Median | p95 | Median | p95 | Median | p95 | Median | p95 | ||||
Massinläggning, 250 000 posterSkrivgenomströmning med sex sekundärindex redan på plats. Skrivningar | 250 000 | 46 900 rows/s | 27 700 rows/s | 19 300 rows/s | 12 000 rows/s | 3 720 rows/s | 2 430 rows/s | 12 000 rows/s | 3 900 rows/s | 42 200 rows/s | 13 300 rows/s | 9 430 rows/s | 1 820 rows/s | 9 480 rows/s | 6 620 rows/s | MongoDB 2.43× | |
Punktläsning på identifierare, 200 anrop200 uppslag på primärnyckel i följd, ett tur och retur vardera. Nyckelåtkomst | 200 | 71 ms | 104 ms | 105 ms | 150 ms | 346 ms | 528 ms | 118 ms | 147 ms | 162 ms | 292 ms | 2.97 s | 3.04 s | — | — | MongoDB 1.49× | |
Alla mätvärden för en besiktningVarje underordnad post till en förälder, på en indexerad främmande nyckel. Nyckelåtkomst | 494 | 5.0 ms | 6.2 ms | 2.1 ms | 5.8 ms | 40 ms | 82 ms | 5.7 ms | 11 ms | 21 ms | 146 ms | 261 ms | 308 ms | 18.9 s | 24.8 s | Postgres 2.38× | |
Första sorterade sidan, 50 raderSida ett av en besiktnings mätvärden, sorterade på mätdatum med det senaste först. Sidindelning | 50 | 1.6 ms | 2.2 ms | 1.3 ms | 2.1 ms | 37 ms | 78 ms | 9.2 ms | 18 ms | 30 ms | 112 ms | 523 ms | 647 ms | 22.7 s | 28.6 s | Postgres 1.28× | |
Djup sida, sida 200Hoppa över 9 950 rader och returnera de 50 följande. Det en numrerad bläddrare ber om. Sidindelning | 50 | 5.2 ms | 6.6 ms | 46 ms | 76 ms | 43 ms | 176 ms | 233 ms | 350 ms | 91 ms | 402 ms | 1.09 s | 1.21 s | 2.67 s | 4.12 s | MongoDB 8.83× | |
Filtrerad genomsökning på ett oindexerat booleskt fältVarje post där en godkännandeflagga är falsk. Indexerat på ingen av dem. Genomsökningar och filter | 10 000 | 88 ms | 127 ms | 48 ms | 119 ms | 102 ms | 283 ms | 448 ms | 837 ms | 144 ms | 318 ms | 2.20 s | 3.35 s | 2.39 s | 3.30 s | Postgres 1.85× | |
Intervallsökning på ett oindexerat talEn indexerad likhet plus ett större-än på ett oindexerat mätvärde. Genomsökningar och filter | 165 | 2.9 ms | 4.3 ms | 1.5 ms | 8.8 ms | 35 ms | 76 ms | 4.7 ms | 21 ms | 9.3 ms | 45 ms | 252 ms | 297 ms | 18.5 s | 24.9 s | Postgres 1.91× | |
Exakt räkning av hela samlingenHur många poster finns det. Inte en uppskattning. Arbete över hela samlingen | 250 000 | 74 ms | 100 ms | 28 ms | 95 ms | 331 ms | 1.40 s | 3.16 s | 4.60 s | 1.14 s | 2.73 s | 28.8 s | 31.8 s | 12.8 s | 15.7 s | Postgres 2.64× | |
Läs in hela samlingenVarje post, deserialiserad in i applikationen. Arbete över hela samlingen | 250 000 | 1.77 s | 2.24 s | 554 ms | 1.47 s | 748 ms | 1.06 s | 5.52 s | 10.0 s | 1.70 s | 3.60 s | 31.0 s | 36.3 s | 28.8 s | 33.8 s | Postgres 3.19× | |
Metod
- Fem fullständiga rundor. Varje runda river alla sju motorerna, sår om 250 000 rader i var och en och kör om varje scenario, så skrivkolumnen är fem oberoende fyllningar och läskolumnerna fem oberoende processer snarare än fem stickprov ur en
- Motorernas ORDNING roterar ett steg per runda. En fast ordning parar varje motor med samma maskintillstånd varje gång — först på en vilande maskin, sist efter att sex motorer bearbetat en och samma disk — och den glidningen går annars inte att skilja från motorn
- Publicerade siffror slår samman råvärdena från alla fem rundorna, 50 iterationer per läscell och 250 klumptider per skrivcell, och redovisar en median och en p95 över hela mängden
- Ett scenario som gick över tidsgränsen bidrar med inga stickprov och står obesvarat. En motor som misslyckas med fyra rundor och klarar den femte har inte förtjänat en median
- 10 iterationer per runda och scenario, 2 uppvärmningar förkastade, 200 punktläsningar i följd per iteration
- Varje LÄSNING går genom applikationens datatjänst, frågehanterare, adapterladdare och datalager — aldrig genom drivrutinen
- Skrivkolumnen går in ett steg lägre. Såmaskinen anropar motoradapterns create_many direkt, så massinläggningen är adapter plus motor utan datatjänsten ovanför — dp-kod i båda fallen och samma djup i varje motor, men inte samma djup som läskolumnerna
- Mätningen skriver in i sin egen databas, fb_bench, så att alla sju motorerna håller exakt 250 000 rader och ingen bär produktionsdata
- Radernas IDENTITET jämfördes innan någon tid togs: varje scenario spelades om i varje motor, _id-mängden sammanfattades, och sammanfattningarna krävdes stämma överens — inte bara antalen
- Indexpariteten kontrollerades vid mättillfället i varje motor och varje runda, och körningen vägrar redovisa en siffra när en motor bär ett index som paritetsuppsättningen inte deklarerar
- Den mätande processen utfärdar ingen DDL alls, så ingenting den gör kan ändra den indexuppsättning den mäter mot
- Skrivningarna mättes som en fyllning från tomt med de sex paritetsindexen redan på plats, i 50 klumpar om 5 000 rader per runda
- Motorversionerna hämtades ur varje servers eget gränssnitt i stället för att skrivas ned för hand
- Ett tak på 120 sekunder per iteration — en motor som överskrider det bokförs som en tidsgräns i stället för att lämnas tom
Indexparitet
- Alla sju motorerna: sekundärindex på _type, _besiktning_id, _system_id, _ventil_id, _room_id och _anmarkning_id
- IndexUPPSÄTTNINGEN kommer ur en enda deklaration i kodbasen, läst av varje adapter, så ingen motor kan glida ifrån en annan
- Närvarande i varje motor medan raderna skrevs, inte tillagda efteråt, i var och en av de fem rundorna
- Ingen motor bär ett index som en annan saknar. Varje motor gick in i varje scenario med sin primärnyckel och de sex, verifierat ur dess egen katalog omedelbart före den första mätningen i varje runda
- Det här är rättelsen av körning E. PostgreSQL och CockroachDB bar fem adapterindex där, ett inverterat GIN över hela dokumentet bland dem, och skrivkolumnen mätte det
- FerretDB:s sex paritetsindex skapades, bekräftades och konstaterades finnas som b-träd i dess underliggande PostgreSQL — och användes aldrig en enda gång
Vad körningen inte visar
- Skrivkolumnen är en fyllning från TOMT, som körning C och körning E snarare än körning D:s tillägg till en befolkad samling. Bara körningar som mäter samma form kan läsas mot varandra.
- Varje anrop var sekventiellt. Ingenting här säger något om beteende under samtidighet, vilket är där ScyllaDB, Cassandra och CockroachDB är byggda för att löna sig.
- En nod var, utvecklarinställningar, alla sex containrarna på en och samma maskin vid sidan av en MongoDB installerad direkt på värden. Ingen motor fick en egen värd.
- MongoDB kör direkt på värden över loopback medan de andra sex korsar en containergräns under WSL2. Det gynnar MongoDB och korrigeras inte för.
- CockroachDB är med bred marginal den minst upprepbara motorn här. Dess exakta räkning låg mellan 175 ms och 710 ms över de fem rundorna och dess punktläsning mellan 248 ms och 505 ms, utan samband med dess plats i ordningen. Dess median är en median över en genuint bred fördelning, och det är p95 som är siffran att läsa.
- Cassandras svans är den andra värd att läsa. Dess besiktningsuppslag medianar 21,4 ms och p95:ar 146 ms, och dess första sida medianar 30 ms och p95:ar 112 ms — ungefär en femtedel av anropen kostar flera gånger det typiska.
- Djup sida och filtrerad genomsökning är fönster över en OSORTERAD mängd — ingen sortering begärs, så vilka 50 rader som är sida 200 och vilka 10 000 rader taket returnerar är motorns egen naturliga ordning. Varje motor returnerade samma ANTAL i båda; radmängderna skiljer sig legitimt, och verifieringssteget namnger dem i stället för att dölja dem.
- ScyllaDB och Cassandra kunde inte betjäna COUNT(*) över 250 000 rader som ett enda anrop — Cassandra vägrade med READ_FAILURE och ScyllaDB med READ_TIMEOUT — så deras räkning är en sidindelad genomsökning. Det är adaptern som gör vad en produktionsimplementation måste göra, och det är därför deras räknekolumn står i sekunder i stället för millisekunder.
- Körning E:s siffror står kvar på sidan. De är inte felaktiga mätningar; de är korrekta mätningar av en uppsättning där två motorer bar fem index som de andra fem saknade, tagna en gång.
Körning E — sju motorer, lika villkor, egen databas
Drop-in-jämförelseMot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Referensmotor — varje faktor på sidan anges mot den. Dess egen sammanräkning ovan står mot den snabbaste av de andra motorerna i vart och ett av 9 scenarier, medianvärden.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 8 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
| Scenario | Rader | MongoDB | Postgres | Cockroach | ScyllaDB | Cassandra | CouchDB | FerretDB | Faktor | Relativt | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Median | p95 | Median | p95 | Median | p95 | Median | p95 | Median | p95 | Median | p95 | Median | p95 | ||||
Massinläggning, 250 000 posterSkrivgenomströmning med sex sekundärindex redan på plats. Skrivningar | 250 000 | 62 500 rows/s | 43 100 rows/s | 20 200 rows/s | 15 200 rows/s | 285 rows/s | 226 rows/s | 25 300 rows/s | 16 600 rows/s | 48 500 rows/s | 21 200 rows/s | 10 900 rows/s | 8 980 rows/s | 11 400 rows/s | 8 870 rows/s | MongoDB 3.09× | |
Punktläsning på identifierare, 200 anrop200 uppslag på primärnyckel i följd, ett tur och retur vardera. Nyckelåtkomst | 200 | 50 ms | 68 ms | 105 ms | 109 ms | 242 ms | 283 ms | 137 ms | 147 ms | 165 ms | 179 ms | 3.00 s | 3.05 s | — | — | row counts differ | |
Alla mätvärden för en besiktningVarje underordnad post till en förälder, på en indexerad främmande nyckel. Nyckelåtkomst | 494 | 3.5 ms | 4.0 ms | 2.0 ms | 2.1 ms | 11 ms | 12 ms | 6.9 ms | 7.6 ms | 21 ms | 34 ms | 249 ms | 254 ms | 16.0 s | 16.4 s | Postgres 1.76× | |
Första sorterade sidan, 50 raderSida ett av en besiktnings mätvärden, sorterade på mätdatum med det senaste först. Sidindelning | 50 | 1.5 ms | 2.0 ms | 1.1 ms | 1.4 ms | 10 ms | 12 ms | 13 ms | 15 ms | 48 ms | 63 ms | 250 ms | 254 ms | 19.4 s | 20.1 s | Postgres 1.31× | |
Djup sida, sida 200Hoppa över 9 950 rader och returnera de 50 följande. Det en numrerad bläddrare ber om. Sidindelning | 50 | 5.4 ms | 6.1 ms | 42 ms | 44 ms | 20 ms | 26 ms | 7.58 s | 10.6 s | 1.51 s | 1.63 s | 29.4 s | 29.6 s | 2.49 s | 2.59 s | MongoDB 7.72× | |
Filtrerad genomsökning på ett oindexerat booleskt fältVarje post där en godkännandeflagga är falsk. Indexerat på ingen av dem. Genomsökningar och filter | 10 000 | 67 ms | 111 ms | 36 ms | 45 ms | 42 ms | 140 ms | 5.09 s | 5.52 s | 1.44 s | 1.51 s | 26.6 s | 26.8 s | 2.25 s | 2.34 s | Postgres 1.87× | |
Intervallsökning på ett oindexerat talEn indexerad likhet plus ett större-än på ett oindexerat mätvärde. Genomsökningar och filter | 165 | 2.3 ms | 2.9 ms | 1.3 ms | 1.5 ms | 9.8 ms | 20 ms | 3.8 ms | 4.7 ms | 7.7 ms | 8.0 ms | 240 ms | 252 ms | 15.4 s | 16.1 s | Postgres 1.7× | |
Exakt räkning av hela samlingenHur många poster finns det. Inte en uppskattning. Arbete över hela samlingen | 250 000 | 71 ms | 74 ms | 24 ms | 26 ms | 195 ms | 1.28 s | 5.07 s | 5.16 s | 1.44 s | 1.49 s | 29.3 s | 29.4 s | 11.4 s | 11.5 s | Postgres 2.95× | |
Läs in hela samlingenVarje post, deserialiserad in i applikationen. Arbete över hela samlingen | 250 000 | 1.89 s | 2.01 s | 488 ms | 508 ms | 533 ms | 567 ms | 5.10 s | 5.18 s | 1.45 s | 1.48 s | 29.4 s | 29.7 s | 24.9 s | 25.7 s | Postgres 3.87× | |
Metod
- Median av 10 iterationer, 2 uppvärmningar förkastade, p95 redovisad bredvid
- 200 punktläsningar i följd per iteration
- Varje LÄSNING går genom applikationens datatjänst, frågehanterare, adapterladdare och datalager — aldrig genom drivrutinen
- Skrivkolumnen går in ett steg lägre. Såmaskinen anropar motoradapterns create_many direkt, så massinläggningen är adapter plus motor utan datatjänsten ovanför — dp-kod i båda fallen och samma djup i varje motor, men inte samma djup som läskolumnerna
- Mätningen skriver in i sin egen databas, fb_bench, så att alla sju motorerna håller exakt 250 000 rader och ingen bär produktionsdata
- Radantalen jämfördes mellan alla sju motorerna i varje scenario innan någon tid redovisades
- Skrivningarna mättes som en fyllning från tomt med de sex paritetsindexen redan på plats, i 50 klumpar om 5 000 rader — så skrivkolumnen har en median och en p95 som varje annan rad, inte ett enda genomsnitt av väggklocka
- Motorversionerna hämtades ur varje servers eget gränssnitt i stället för att skrivas ned för hand
- Ett tak på 120 sekunder per iteration — en motor som överskrider det bokförs som en tidsgräns i stället för att lämnas tom
Indexparitet
- Alla sju motorerna: sekundärindex på _type, _besiktning_id, _system_id, _ventil_id, _room_id och _anmarkning_id
- IndexUPPSÄTTNINGEN kommer ur en enda deklaration i kodbasen, läst av varje adapter, så ingen motor kan glida ifrån en annan
- Närvarande i varje motor medan raderna skrevs, inte tillagda efteråt
- PostgreSQL och CockroachDB bär dessutom fem index skapade av adaptern, GIN inräknat — verifierat med EXPLAIN som oanvändbara för varje scenario här, så de är en skrivkostnad och ingen läsfördel
- FerretDB:s sex paritetsindex skapades, bekräftades och konstaterades finnas som b-träd i dess underliggande PostgreSQL — och användes aldrig en enda gång
Vad körningen inte visar
- Skrivkolumnen är en fyllning från TOMT. Körning D mätte ett tillägg till en befolkad samling och körning C mätte en fyllning. Bara körningar som mäter samma form kan läsas mot varandra, och den här matchar körning C:s form snarare än körning D:s.
- Varje anrop var sekventiellt. Ingenting här säger något om beteende under samtidighet, vilket är där ScyllaDB, Cassandra och CockroachDB är byggda för att löna sig.
- En nod var, utvecklarinställningar, alla sex containrarna på en och samma maskin vid sidan av en MongoDB installerad direkt på värden. Ingen motor fick en egen värd.
- MongoDB kör direkt på värden över loopback medan de andra sex korsar en containergräns under WSL2. Det gynnar MongoDB och korrigeras inte för.
- ScyllaDB:s COUNT(*) överskred serverns egen lästidsgräns (kod 4608) på den här datamängden, så dess räkning är en sidindelad genomsökning i stället för en aggregering på serversidan. Cassandras gjorde samma sak i körning D och gör det här.
- CockroachDB:s count() returnerade en sträng i stället för ett tal, eftersom dess ::int är INT8 och node-postgres lämnar tillbaka int8 som text. Radantalen stämde; typerna gjorde det inte. Rättat i adaptern efter körningen — siffrorna nedan mättes med bristen på plats, vilket inte kostade något eftersom bara paritetskontrollen läste värdet.
Körning D — sju motorer, strikt indexparitet
Drop-in-jämförelseMot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Referensmotor — varje faktor på sidan anges mot den. Dess egen sammanräkning ovan står mot den snabbaste av de andra motorerna i vart och ett av 9 scenarier, medianvärden.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 9 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 8 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
| Scenario | Rader | MongoDB | Postgres | Cockroach | ScyllaDB | Cassandra | CouchDB | FerretDB | Faktor | Relativt | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Median | p95 | Median | p95 | Median | p95 | Median | p95 | Median | p95 | Median | p95 | Median | p95 | ||||
Massinläggning, 250 000 posterSkrivgenomströmning med sex sekundärindex redan på plats. Skrivningar | 250 000 | 44 238 rows/s | — | 11 155 rows/s | — | 536 rows/s | — | 13 305 rows/s | — | 31 328 rows/s | — | 10 001 rows/s | — | 10 399 rows/s | — | MongoDB 3.97× | |
Punktläsning på identifierare, 200 anrop200 uppslag på primärnyckel i följd, ett tur och retur vardera. Nyckelåtkomst | 200 | 62 ms | 75 ms | 98 ms | 106 ms | 222 ms | 270 ms | 103 ms | 112 ms | 150 ms | 171 ms | 3.06 s | 3.08 s | — | — | MongoDB 1.59× | |
Alla mätvärden för en besiktningVarje underordnad post till en förälder, på en indexerad främmande nyckel. Nyckelåtkomst | 494 | 3.8 ms | 4.2 ms | 1.9 ms | 2.5 ms | 11 ms | 12 ms | 4.6 ms | 5.3 ms | 8.9 ms | 24 ms | 261 ms | 266 ms | 16.7 s | 18.8 s | Postgres 2.01× | |
Första sorterade sidan, 50 raderSida ett av en besiktnings mätvärden, sorterade på mätdatum med det senaste först. Sidindelning | 50 | 1.6 ms | 1.7 ms | 1.1 ms | 1.3 ms | 9.5 ms | 11 ms | 9.7 ms | 11 ms | 16 ms | 17 ms | 251 ms | 263 ms | 20.5 s | 20.7 s | Postgres 1.45× | |
Djup sida, sida 200Hoppa över 9 950 rader och returnera de 50 följande. Det en numrerad bläddrare ber om. Sidindelning | 50 | 5.5 ms | 6.1 ms | 4.6 ms | 5.1 ms | 11 ms | 15 ms | 5.15 s | 5.20 s | 1.57 s | 1.66 s | 30.0 s | 30.7 s | 2.50 s | 2.56 s | Postgres 1.18× | |
Filtrerad genomsökning på ett oindexerat booleskt fältVarje post där en godkännandeflagga är falsk. Indexerat på ingen av dem. Genomsökningar och filter | 10 000 | 72 ms | 104 ms | 35 ms | 41 ms | 39 ms | 55 ms | 5.09 s | 5.13 s | 1.49 s | 1.54 s | 27.7 s | 28.5 s | 2.29 s | 2.32 s | Postgres 2.05× | |
Intervallsökning på ett oindexerat talEn indexerad likhet plus ett större-än på ett oindexerat mätvärde. Genomsökningar och filter | 165 | 2.5 ms | 2.9 ms | 1.4 ms | 1.4 ms | 10 ms | 13 ms | 3.9 ms | 4.4 ms | 7.5 ms | 8.2 ms | 252 ms | 261 ms | 16.8 s | 17.3 s | Postgres 1.76× | |
Exakt räkning av hela samlingenHur många poster finns det. Inte en uppskattning. Arbete över hela samlingen | 250 000 | 72 ms | 73 ms | 26 ms | 28 ms | 169 ms | 214 ms | 5.11 s | 5.15 s | 1.49 s | 1.53 s | 29.8 s | 34.0 s | 11.6 s | 11.9 s | row counts differ | |
Läs in hela samlingenVarje post, deserialiserad in i applikationen. Arbete över hela samlingen | 250 000 | 1.55 s | 1.64 s | 522 ms | 653 ms | 531 ms | 688 ms | 5.12 s | 5.21 s | 1.50 s | 1.54 s | 29.7 s | 29.9 s | 25.8 s | 26.2 s | row counts differ | |
Metod
- Median av 10 iterationer, 2 uppvärmningar förkastade, p95 redovisad bredvid
- 200 punktläsningar i följd per iteration
- Varje LÄSNING går genom applikationens datatjänst, frågehanterare, adapterladdare och datalager — aldrig genom drivrutinen
- Skrivkolumnen går in ett steg lägre. Såmaskinen anropar motoradapterns create_many direkt, så massinläggningen är adapter plus motor utan datatjänsten ovanför — dp-kod i båda fallen och samma djup i varje motor, men inte samma djup som läskolumnerna
- Radantalen jämfördes mellan alla sju motorerna innan någon tid redovisades
- Läsningarna mättes vid 250 000 rader; skrivningarna mättes efteråt genom att lägga ytterligare 250 000 ovanpå, så varje motor skriver in i en befolkad och indexerad samling
- Motorversionerna hämtades ur varje servers eget gränssnitt i stället för att skrivas ned för hand
- Ett tak på 120 sekunder per iteration — en motor som överskrider det bokförs som en tidsgräns i stället för att lämnas tom
Indexparitet
- Alla sju motorerna: sekundärindex på _type, _besiktning_id, _system_id, _ventil_id, _room_id och _anmarkning_id
- IndexUPPSÄTTNINGEN kommer ur en enda deklaration i kodbasen, läst av varje adapter, så ingen motor kan glida ifrån en annan
- Närvarande i varje motor medan raderna skrevs, inte tillagda efteråt
- godkand och varde lämnades oindexerade med avsikt — men se förbehållet: PostgreSQL och CockroachDB bär ytterligare index skapade av adaptern, däribland ett GIN-index över hela dokumentet
Vad körningen inte visar
- PostgreSQL och CockroachDB kör INTE oindexerat i genomsökningsscenarierna. dp-adaptern skapar idx_fb_matning_doc_gin — ett GIN-index över hela JSONB-dokumentet — vid sidan av de sex paritetsindexen, så deras filtrerade genomsökning och intervallsökning är indexstödda där de andra fem motorerna genomsöker.
- Skrivkolumnen är ett TILLÄGG till en samling som redan håller 250 000 rader. Körning C mätte en fyllning av en tom. De två skrivjämförelserna mäter olika arbete och får inte läsas mot varandra.
- MongoDB:s radantal är 250 007, inte 250 000 — den håller också sju verkliga mätvärdesrader från Franska Bukten. Skillnaden på sju rader lämnas kvar i stället för att raderas ur en levande samling.
- Varje anrop var sekventiellt. Ingenting här säger något om beteende under samtidighet, vilket är där ScyllaDB, Cassandra och CockroachDB är byggda för att löna sig.
- En nod var, utvecklarinställningar, alla sju containrarna på en och samma maskin. Tomgångsbelastningen låg under 1,5 % per container under körningen, men ingen motor fick en egen värd.
- FerretDB:s indexerade uppslag blev långsammare än dess fullständiga genomsökningar, vilket tyder på att paritetsindexen togs emot och sedan inte användes. Det är oförklarat och redovisas som mätt snarare än tolkat.
Körning C — strikt indexparitet, indexen närvarande under insättningen
Drop-in-jämförelseMot PostgreSQL, i 0 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
Mot PostgreSQL, i 0 scenarier, medianvärden. Ingen samlad faktor anges: spridningen är resultatet.
| Scenario | Rader | MongoDB | ScyllaDB | Faktor | Relativt | ||
|---|---|---|---|---|---|---|---|
| Median | p95 | Median | p95 | ||||
Massinläggning, 250 000 posterSkrivgenomströmning med sex sekundärindex redan på plats. Skrivningar | 250 000 | 11 028 rows/s | — | 17 147 rows/s | — | — | |
Punktläsning på identifierare, 200 anrop200 uppslag på primärnyckel i följd, ett tur och retur vardera. Nyckelåtkomst | 200 | 68 ms | 83 ms | 115 ms | 122 ms | — | |
Alla mätvärden för en besiktningVarje underordnad post till en förälder, på en indexerad främmande nyckel. Nyckelåtkomst | 494 | 4.5 ms | 6.3 ms | 6.1 ms | 6.9 ms | — | |
Första sorterade sidan, 50 raderSida ett av en besiktnings mätvärden, sorterade på mätdatum med det senaste först. Sidindelning | 50 | 1.9 ms | 2.5 ms | 12 ms | 13 ms | — | |
Djup sida, sida 200Hoppa över 9 950 rader och returnera de 50 följande. Det en numrerad bläddrare ber om. Sidindelning | 50 | 6.0 ms | 6.5 ms | 6.74 s | 9.63 s | — | |
Filtrerad genomsökning på ett oindexerat booleskt fältVarje post där en godkännandeflagga är falsk. Indexerat på ingen av dem. Genomsökningar och filter | 10 000 | 80 ms | 147 ms | 6.23 s | 6.56 s | — | |
Intervallsökning på ett oindexerat talEn indexerad likhet plus ett större-än på ett oindexerat mätvärde. Genomsökningar och filter | 165 | 2.5 ms | 3.7 ms | 4.9 ms | 5.7 ms | — | |
Exakt räkning av hela samlingenHur många poster finns det. Inte en uppskattning. Arbete över hela samlingen | 250 000 | 76 ms | 78 ms | 6.34 s | 7.93 s | — | |
Läs in hela samlingenVarje post, deserialiserad in i applikationen. Arbete över hela samlingen | 250 000 | 1.95 s | 2.38 s | 6.43 s | 7.15 s | — | |
Metod
- Median av 10 iterationer, 2 uppvärmningar förkastade, p95 redovisad bredvid
- 200 punktläsningar per iteration
- Varje LÄSNING går genom applikationens datatjänst, frågehanterare, adapterladdare och datalager — aldrig genom drivrutinen
- Skrivkolumnen går in ett steg lägre. Såmaskinen anropar motoradapterns create_many direkt, så massinläggningen är adapter plus motor utan datatjänsten ovanför — dp-kod i båda fallen och samma djup i varje motor, men inte samma djup som läskolumnerna
- Radantalen jämfördes mellan motorerna innan någon tid redovisades, och de stämde i varje scenario
- Hela produktionsdatabasen migrerades först: 41 samlingar, noll avvikelser i radantal
Indexparitet
- Båda motorerna: sekundärindex på _type, _besiktning_id, _system_id, _ventil_id, _room_id och _anmarkning_id
- Verifierat genom att läsa varje motors egen indexkatalog, inte genom att lita på uppsättningsskriptet
- Närvarande i båda motorerna medan de 250 000 raderna skrevs
- godkand och varde lämnades oindexerade på båda sidor med avsikt, så att genomsökningsscenarierna är genuint oindexerat arbete för alla
Vad körningen inte visar
- Att MongoDB gör nyckeluppslag snabbare i allmänhet — punktläsningen var sekventiell, och ScyllaDB korsade en nätverksgräns som MongoDB inte gjorde.
- Någonting om samtidighet. Varje anrop i den här körningen var sekventiellt; ScyllaDB:s arkitektur är byggd för att löna sig under last, och last lades inte på.
- Någonting om beteende över flera noder, replikering eller redundans. En nod, utvecklarläge.
- Hur bra någon av motorerna skulle kunna prestera efter en omarbetning kring den — det är ett annat test, och det är inte det här.
Körning B — paritetsindexen skapade efter insådden
Drop-in-jämförelse| Scenario | Rader | MongoDB | ScyllaDB | Faktor | Relativt | ||
|---|---|---|---|---|---|---|---|
| Median | p95 | Median | p95 | ||||
Punktläsning på identifierare, 200 anrop200 uppslag på primärnyckel i följd, ett tur och retur vardera. Nyckelåtkomst | 200 | 56 ms | 66 ms | 116 ms | 119 ms | — | |
Alla mätvärden för en besiktningVarje underordnad post till en förälder, på en indexerad främmande nyckel. Nyckelåtkomst | 494 | 4.5 ms | 5.2 ms | 4.9 ms | 6.8 ms | — | |
Första sorterade sidan, 50 raderSida ett av en besiktnings mätvärden, sorterade på mätdatum med det senaste först. Sidindelning | 50 | 1.6 ms | 2.2 ms | 9.7 ms | 21 ms | — | |
Djup sida, sida 200Hoppa över 9 950 rader och returnera de 50 följande. Det en numrerad bläddrare ber om. Sidindelning | 50 | 5.1 ms | 6.0 ms | 5.51 s | 5.62 s | — | |
Filtrerad genomsökning på ett oindexerat booleskt fältVarje post där en godkännandeflagga är falsk. Indexerat på ingen av dem. Genomsökningar och filter | 10 000 | 81 ms | 89 ms | 5.44 s | 5.54 s | — | |
Intervallsökning på ett oindexerat talEn indexerad likhet plus ett större-än på ett oindexerat mätvärde. Genomsökningar och filter | 165 | 2.8 ms | 8.4 ms | 4.6 ms | 6.3 ms | — | |
Exakt räkning av hela samlingenHur många poster finns det. Inte en uppskattning. Arbete över hela samlingen | 250 000 | 66 ms | 68 ms | 5.45 s | 5.47 s | — | |
Läs in hela samlingenVarje post, deserialiserad in i applikationen. Arbete över hela samlingen | 250 000 | 1.99 s | 2.50 s | 5.48 s | 5.56 s | — | |
Metod
- Median av 10 iterationer, 2 uppvärmningar förkastade
- 200 punktläsningar per iteration
- MongoDB såddes först och indexerades sedan — det är bristen
- Ingen skrivmätning togs, eftersom en giltig sådan inte var möjlig
Indexparitet
- MongoDB: sex sekundärindex, skapade efter insådden
- ScyllaDB: samma sex, skapade med tabellen och närvarande under insättningen
- Paritet i fält, men inte i livscykel
Vad körningen inte visar
- Varje påstående om skrivgenomströmning. Det finns inget i den här körningen.
- Att ett index skapat efter en massinläggning beter sig likadant som ett som underhållits genom den.
Körning A — ingen indexparitet
Drop-in-jämförelse| Scenario | Rader | MongoDB | ScyllaDB | Faktor | Relativt | ||
|---|---|---|---|---|---|---|---|
| Median | p95 | Median | p95 | ||||
Massinläggning, 250 000 posterSkrivgenomströmning med sex sekundärindex redan på plats. Skrivningar | 250 000 | 27 105 rows/s | — | 21 077 rows/s | — | — | |
Punktläsning på identifierare, 200 anrop200 uppslag på primärnyckel i följd, ett tur och retur vardera. Nyckelåtkomst | 200 | 51 ms | 61 ms | 114 ms | 124 ms | — | |
Alla mätvärden för en besiktningVarje underordnad post till en förälder, på en indexerad främmande nyckel. Nyckelåtkomst | 494 | 88 ms | 93 ms | 5.2 ms | 6.5 ms | — | |
Första sorterade sidan, 50 raderSida ett av en besiktnings mätvärden, sorterade på mätdatum med det senaste först. Sidindelning | 50 | 86 ms | 88 ms | 9.4 ms | 18 ms | — | |
Djup sida, sida 200Hoppa över 9 950 rader och returnera de 50 följande. Det en numrerad bläddrare ber om. Sidindelning | 50 | 5.9 ms | 6.6 ms | 6.12 s | 20.8 s | — | |
Filtrerad genomsökning på ett oindexerat booleskt fältVarje post där en godkännandeflagga är falsk. Indexerat på ingen av dem. Genomsökningar och filter | 10 000 | 85 ms | 93 ms | 5.76 s | 7.36 s | — | |
Intervallsökning på ett oindexerat talEn indexerad likhet plus ett större-än på ett oindexerat mätvärde. Genomsökningar och filter | 165 | 94 ms | 103 ms | 4.8 ms | 8.1 ms | — | |
Exakt räkning av hela samlingenHur många poster finns det. Inte en uppskattning. Arbete över hela samlingen | 250 000 | 75 ms | 78 ms | 5.61 s | 6.01 s | — | |
Läs in hela samlingenVarje post, deserialiserad in i applikationen. Arbete över hela samlingen | 250 000 | 2.30 s | 2.85 s | 5.63 s | 5.94 s | — | |
Metod
- Median av 10 iterationer, 2 uppvärmningar förkastade
- 200 punktläsningar per iteration
- Varje LÄSNING går genom applikationens datatjänst, inte genom drivrutinen
- Skrivkolumnen går in ett steg lägre. Såmaskinen anropar motoradapterns create_many direkt, så massinläggningen är adapter plus motor utan datatjänsten ovanför — dp-kod i båda fallen och samma djup i varje motor, men inte samma djup som läskolumnerna
Indexparitet
- MongoDB: enbart standardindexet på identifieraren
- ScyllaDB: sex sekundärindex, skapade automatiskt av adaptern
- Ingen paritet — det är just den bristen körningen finns för att visa
Vad körningen inte visar
- Ingenting. Ingen jämförelse i den här tabellen är giltig.
- Att lägga till de sex motsvarande MongoDB-indexen flyttade besiktningsuppslaget från 88 ms till 4,5 ms och den sorterade första sidan från 86 ms till 1,6 ms.
- Alla tre ScyllaDB-vinster försvann så snart indexuppsättningarna stämde överens.
Motorerna
MongoDB
Dokumentdatabas- Version
- 8.2.3
- Drivrutin
- mongodb 7.2.0
Byggd för
- Flexibla dokumentstrukturer
- Allmänna sekundärindex
- Fri filtrering och sortering
- Intervallfrågor och aggregering
- Frågemönster som ändras efter lansering
Så driftsattes den
- Docker-container från avbildningen mongo:8.0, ensam på en m5d.2xlarge — 8 vCPU, 32 GB, lokal NVMe
- Ingen minnesgräns, ingen processorgräns, ingen granne, ingenting annat installerat på maskinen
- Genom körning F var den den ENDA motorn som körde direkt på värden över loopback utan tak medan sex andra delade samma bärbara dator i containrar. Det var den vänligaste driftsformen i jämförelsen och den är borta: den vann två lässcenarier där och inga här
ScyllaDB
Bredkolumnsdatabas- Version
- 6.2.3-0.20250119.bff9ddde1283, CQL 3.3.1 (Cassandra-compat 3.0.8)
- Drivrutin
- cassandra-driver 4.9.0, consistency LOCAL_ONE, fetch size 5000
Byggd för
- Hög skrivgenomströmning
- Förutsägbart låg fördröjning under samtidighet
- Horisontell skalning över noder
- Läsningar på partitionsnyckel
- Datamodeller designade kring kända frågor
Så driftsattes den
- Docker-container från avbildningen scylladb/scylla:6.2, ensam på en m5d.2xlarge
- --smp 8 --memory 24G --overprovisioned 0 --developer-mode 1 — varje kärna på maskinen, mot två skärvor och 4 GB i körning F
- Seastar reserverar utrymme utöver vad --memory ber om, och vägrar starta när summan överstiger vad maskinen faktiskt har: 24G av 32 är taket som startar
- Tog punktläsningen rakt av här på 62,2 ms, ett scenario den kom trea i när den hade två skärvor
- Dess COUNT(*) överskrider serverns egen lästidsgräns på 250 000 rader (kod 4608), så adaptern räknar med en sidindelad genomsökning — samma reservväg som Cassandra behöver
PostgreSQL
Relationsdatabas- Version
- 17.10 (Debian 17.10-1.pgdg13+1)
- Drivrutin
- pg 8.22.0
Byggd för
- Relationell integritet och transaktioner
- Sammansatta join och aggregeringar
- Blandad läs- och skrivbelastning på en nod
Så driftsattes den
- Docker-container från avbildningen postgres:17, ensam på en m5d.2xlarge, ingen minnesgräns
- Genom körning F kördes den med tak på 2 GB och DELADE den buffertpoolen med FerretDB, som lagrade sin egen kopia av alla 250 000 dokument i samma server. Att ge den maskinen tog dess djupa sida från 46,1 ms till 4,16 ms — elva gånger snabbare på en långsammare processor
- Dokumenten lagras som JSONB, indexerade fält som index på uttrycket doc ->> 'field'
- Genom körning E bar den fem extra index skapade av adaptern ovanpå de sex paritetsindexen, ett GIN-index över hela dokumentet bland dem. Från körning F bär den de sex och sin primärnyckel, som varje annan motor
- De fem gav den ingenting på läsningarna i något av fallen. EXPLAIN placerar den filtrerade genomsökningen på en Parallel Seq Scan: dp skickar doc ->> 'field', och ett GIN-index med jsonb_ops svarar på innehåll, inte på textextraktion. De var enbart en skrivkostnad
Apache Cassandra
Bredkolumnsdatabas- Version
- 5.0.8, CQL 3.4.7
- Drivrutin
- cassandra-driver 4.9.0, consistency LOCAL_ONE, fetch size 5000
Byggd för
- Hög skrivgenomströmning
- Replikering över flera datacenter
- Tabelldesign styrd av frågorna
Så driftsattes den
- Docker-container från avbildningen cassandra:5.0, ensam på en m5d.2xlarge, ingen minnesgräns och JVM dimensionerad mot hela de 32 GB
- Kördes vid 3,686 GB mot ett tak på 4 GB i körning F, under verkligt tryck från skräpsamlingen hela tiden. Att ta bort taket gjorde den inte snabbare i absoluta tal — dess skrivtakt föll från 42 200 rader per sekund till 28 300 — men varje motor blev långsammare på den här hårdvaran, och den höll andraplatsen på skrivningar i båda körningarna
- Delar hela CQL-adaptern med ScyllaDB, så allt som skiljer de två åt är körtiden och ingenting annat
- Dess COUNT(*) överskred serverns egen lästidsgräns på 5 sekunder, så adaptern räknar med en sidindelad genomsökning i stället
Couchbase
DokumentdatabasByggd för
- Nyckel–värde-läsningar ur cache med låg fördröjning
- SQL-liknande frågor över dokument
- Att skala läs- och indextjänsterna oberoende av varandra
Så driftsattes den
- Ännu inte driftsatt.
CockroachDB
Distribuerad relationsdatabas- Version
- CCL v24.3.5 (built 2025-02-03, go1.22.8)
- Drivrutin
- pg 8.22.0 — the PostgreSQL driver, unchanged
Byggd för
- Horisontell skalning utan att ge upp SQL
- Serialiserbara distribuerade transaktioner
- Att överleva förlusten av en nod eller en region
Så driftsattes den
- Docker-container från avbildningen cockroachdb/cockroach:v24.3.5, en nod, --insecure, ensam på en m5d.2xlarge, ingen minnesgräns
- Delar hela PostgreSQL-adaptern och samma index på uttryck
- Bar samma fem extra index skapade av adaptern som PostgreSQL genom körning E, GIN inräknat. Att ta bort dem inför körning F flyttade dess skrivgenomströmning med en faktor tretton — dess schemaändringar är asynkrona, så den hade byggt ett inverterat index över 250 000 dokument under mätningen
- Returnerar sina radantal som strängar där varje annan motor returnerar tal
- Den var den minst upprepbara motorn i uppsättningen på den delade bärbara datorn — dess exakta räkning låg mellan 175 ms och 710 ms över körning F:s fem rundor. Ensam på en maskin drog den ihop sig till en p95 inom 1,1× av sin median i samma scenario, vilket tyder på att spridningen var trängsel snarare än motorn
- Skriver fortfarande långsammare än allt annat här med bred marginal: 2 610 rader per sekund, och 100,8 sekunder för en fyllning MongoDB gör på 8,4
- På en maskin med 2 GB och en kärna kunde den inte fullborda körningen: sju rundor av tio blev klara, två dog med klienten rapporterande en avbruten anslutning mitt i insådden, och en hängde sig hela tretimmarstaket. Dess fyllning där går i 1 140 rader per sekund — 286 sekunder, mot MongoDB:s 12,8 — och dess publicerade kolumn är sammanslagen ur de sju som överlevde
Apache CouchDB
Dokumentdatabas- Version
- 3.4.3 (e12b967d7)
- Drivrutin
- none — CouchDB's whole interface is HTTP and JSON, so fetch is the client
Byggd för
- Replikering mellan likvärdiga noder, även till klienter utan uppkoppling
- Hållbarhet byggd för att krascha
- Läsning genom förberäknade vyer
Så driftsattes den
- Docker-container från avbildningen couchdb:3.4, ensam på en m5d.2xlarge, ingen minnesgräns
- Motorn som vann mest på att få taket borttaget och ändå förlorade på ett scenario: punktläsning 2 970 ms till 679 ms, räkning 28,8 s till 14,7 s, första sidan 523 ms till 243 ms — och djup sida 1 090 ms till 3 460 ms, tre gånger långsammare
- Har den bredaste svansen i körning G. Dess första sida medianar 243 ms och p95:ar 1 570 ms, och dess filtrerade genomsökning medianar 1 340 ms och p95:ar 7 470 ms — ungefär ett anrop av tjugo kostar sex gånger det typiska
- En CouchDB-databas per dp-samling, vilket gör en exakt räkning till en metadataläsning i stället för en genomsökning
- dp:s fält med inledande understreck är OTILLÅTNA här — CouchDB reserverar det prefixet och svarar doc_validation: Bad special document member: _type. Varje fält byter namn vid skrivning och tillbaka vid läsning.
- Ett Mango-index krävs för att sortera: det här är den enda motorn som vägrar en fråga i stället för att bli långsammare, så adaptern sorterar i applikationen när inget index täcker fältet
- På en maskin med 2 GB och en kärna blev den klar med alla tio rundorna och vägrade sedan två scenarier i var och en av dem: besiktningsuppslaget och första sidan kom tillbaka från POST /_find som en tidsgräns på serversidan, motorn som avböjer frågan i stället för att köra den långsamt
FerretDB
Dokumentlager ovanpå PostgreSQL- Version
- v1.24.0, presenting MongoDB wire 7.0.42
- Drivrutin
- mongodb 7.2.0 — the MongoDB driver, unchanged
Byggd för
- Att behålla MongoDB-drivrutiner och -frågor på en öppen stack
- Att återanvända PostgreSQL:s drift, säkerhetskopior och verktyg
- Att flytta från en dokumentdatabas utan att skriva om frågorna
Så driftsattes den
- Docker-container från avbildningen ghcr.io/ferretdb/ferretdb:1.24.0, ensam på en m5d.2xlarge med en egen PostgreSQL 17.10-container bredvid sig, ingen minnesgräns på någon av dem
- GENOM KÖRNING F VAR DESS UNDERLIGGANDE LAGER DEN POSTGRESQL SOM MÄTTES. Dess data — en andra fullständig kopia av alla 250 000 dokument — låg i buffertpoolen hos motorn i nästa kolumn, med tak på 2 GB. Ingen indexparitetskontroll fångar det, och ingenting i körning F:s utdata visar det
- Att skilja dem åt kostade FerretDB ungefär halva farten rakt igenom och gjorde PostgreSQL elva gånger snabbare på den djupa sidan. Delandet hjälpte aldrig FerretDB; det förstörde PostgreSQL
- Behövde ingen adapterkod alls — dp:s MongoDB-frågor kommer fram oförändrade
- Inga ändringsströmmar, så dp:s prenumerationer kan inte betjänas: den enda funktionsluckan här som inte är en prestandafråga
- Dess indexerade uppslag mäter LÅNGSAMMARE än dess fullständiga genomsökningar, och dess underliggande PostgreSQL säger varför: 302 sekventiella genomsökningar, 67 750 000 lästa tupler, idx_scan = 0 på varje index inklusive det på _id. De sex paritetsindexen finns där som riktiga b-träd och användes aldrig en enda gång.
MariaDB
Relationsdatabas- Version
- 11.4.12-MariaDB-ubu2404
- Drivrutin
- mysql2 3.23.1
Byggd för
- Relationell integritet och transaktioner
- Sammansatta join och aggregeringar
- Direkt ersättare för MySQL-installationer
- Blandad läs- och skrivbelastning på en nod
Så driftsattes den
- Docker-container från avbildningen mariadb:11.4, ensam på en m5d.2xlarge
- innodb-buffer-pool-size=24G. Det är UTJÄMNING, inte trimning: InnoDB öppnar sina datafiler med O_DIRECT — bekräftat på maskinen, @@innodb_flush_method = O_DIRECT — så operativsystemets sidcache backar den inte och förvalet på 128 MB vore i praktiken hela cachen. Varje annan motor här når större delen av maskinen som förval, och att lämna MariaDB på 128 MB hade gjort den till den enda som inte kunde
- max_allowed_packet=256M, eftersom såmaskinen skriver i klumpar om femtusen dokument och varje klump anländer som en INSERT med många rader. Ett protokollkrav från mätverktyget, inte ett prestandareglage
- Ingenting annat är satt. Ingen dimensionering av redo-loggen, ingen trimning av utskrivningen, ingen trådpool
- utf8mb4_bin rakt igenom. Förvalet utf8mb4_general_ci är OKÄNSLIGT för skiftläge, vilket hade fått `equals` att matcha rader som PostgreSQL, MongoDB och CQL alla förkastar — ett annat radantal ur samma filter, och en avvikelse i sammanfattningen som hade sett ut som ett fel i adaptern
- MariaDB KAN INTE indexera ett uttryck. PostgreSQL indexerar doc ->> 'field' direkt och MySQL 8 har funktionella index; MariaDB har ingetdera, så vart och ett av de sex paritetsfälten bär en genererad kolumn och indexet sitter på den kolumnen
- Det gör frågans formulering avgörande snarare än kosmetisk. EXPLAIN på den här tabellen: att referera den genererade kolumnen ger type=ref, key=dpx__besiktning_id, 4 rader. Samma fråga skriven som den inbäddade extraktionen ger type=ALL, key=NULL, fullständig genomsökning. MariaDB skriver inte om det ena till det andra
dpdb
Dokumentdatabas- Version
- built from 0531553347dc, --ram-mb 700
- Drivrutin
- none — fetch over HTTP for queries, a websocket for subscriptions
Byggd för
- Att köra bredvid applikationen på en liten maskin
- Ett minnestak som inte följer datamängden
- Prenumerationer som pushas, som en förstklassig funktion
- dp:s egna frågeformer utan översättningslager
Så driftsattes den
- En enda kompilerad binär under systemd på en STARTER-1xCPU-2GB i se-sto1 — inte en container, eftersom en container inte är hur dpdb driftsätts någonstans
- Den enda motorn på sidan utan avbildning att hämta och utan tjänst att konfigurera bortom en unit-fil och en datakatalog
- Dess minnestak är ett argument (--ram-mb 700) snarare än en cgroup-gräns, vilket är skillnaden raden ovan påstår: motorn begränsar sig själv i stället för att bli begränsad
SQLite
Inbyggd relationsdatabas- Version
- SQLite 3.53.3
- Drivrutin
- node:sqlite, built into Node v24.19.0 — there is no package to install
Byggd för
- Att driftsätta en databas genom att inte skicka med någon
- Lästung belastning på en maskin
- Inbyggda installationer och installationer i kanten utan operatör
- Ingen driftyta alls — ingen port, ingen användare, ingen tjänst
Så driftsattes den
- En STARTER-1xCPU-2GB i se-sto1, som varje annan motor här, och den enda där ingenting installerades på den
- Hela installationssteget är `mkdir /var/lib/dp-sqlite`. Flottans uppsättning lägger Node på maskinen, och Node innehåller redan databasen — den tomheten är fyndet, inte ett förbiseende
- Ingen port, ingen användare, ingen tjänst, ingen container och ingen minnesgräns, eftersom det inte finns någon andra process att begränsa. Motorn kör inuti mätprocessen på mätningens egen tråd
MariaDB behind MaxScale
Proxy framför MariaDB- Version
- MaxScale 23.08.13 (readwritesplit) in front of MariaDB 11.4.12
- Drivrutin
- mysql2 3.23.1 — the same driver, pointed at port 4006
Byggd för
- Anslutningspooler och lastbalansering framför ett kluster
- Uppdelning av läsning och skrivning utan ändringar i applikationen
- Redundansväxling som applikationen aldrig märker
- Filtrering, omskrivning och loggning av frågor på ett ställe
Så driftsattes den
- Docker-container från avbildningen mariadb/maxscale:23.08, på SAMMA m5d.2xlarge som den MariaDB den står framför
- En maskin och inte två med avsikt. Proxyn är den enda variabeln, så processorn, disken, buffertpoolen, datamängden och adaptern måste vara samma fysiska sak snarare än samma specifikation
- readwritesplit, inte readconnroute. readconnroute vidarebefordrar byte utan att förstå dem och hade mätt ett TCP-hopp; readwritesplit TOLKAR varje sats för att avgöra vart den går, vilket är vad en verklig MaxScale-installation gör och där dess kostnad faktiskt sitter
- En server bakom, markerad Master av mariadbmon. Att lägga till repliker hade ändrat motorn såväl som vägen till den, och då hade ingenting särskiljbart återstått att mäta
- Noll rader adapterkod. dp:s MariaDB-frågor kommer fram oförändrade — anslutningssträngen är hela skillnaden i kodbasen, vilket är just det som gör paret till en mätning av proxyn