sql >> Databáze >  >> RDS >> MariaDB

Výkon ovladače MariaDB Java Connector Driver

VÝKON MARIADB JAVA CONNECTOR

Vždy se bavíme o výkonu. Ale vždy jde o to „měřit, nehádat!“.

Na MariaDB Java Connector bylo v poslední době provedeno mnoho vylepšení výkonu. Jaký je tedy aktuální výkon ovladače?

Dovolte mi podělit se o srovnávací výsledek 3 ovladačů jdbc umožňujících přístup k databázi MySQL/MariaDB: DrizzleJDBC, MySQL Connector/J a MariaDB java konektor.

Verze ovladače jsou nejnovější dostupnou verzí GA v době psaní tohoto blogu:

  • MariaDB 1.5.3
  • MySQL 5.1.39
  • Krholení 1.4

BENCHMARK

JMH je rámcový nástroj pro mikro-benchmarking Oracle vyvinutý společností Oracle, dodávaný jako nástroje openJDK, který bude oficiální sadou mikrobenchmarků java 9. Jeho výrazná výhoda oproti jiným frameworkům spočívá v tom, že je vyvíjen stejnými lidmi z Oracle, kteří implementují JIT (Just In Time kompilace) a umožňují vyhnout se většině nástrah mikrobenchmarků.

Zdroj benchmarku: https://github.com/rusher/mariadb-java-driver-benchmark.

Testy jsou docela jednoduché, pokud jste obeznámeni s javou.
Příklad:

public class BenchmarkSelect1RowPrepareText rozšiřuje BenchmarkSelect1RowPrepareAbstract { @Benchmark public String mysql(MyState state) hází Throwable { return select1RowPrepare(state.mysqlConnectionText, state); } @Benchmark public String mariadb(MyState state) throws Throwable { return select1RowPrepare(state.mariadbConnectionText, state); } @Benchmark public String drizzle(MyState state) hází Throwable { return select1RowPrepare(state.drizzleConnectionText, state); } }veřejná abstraktní třída BenchmarkSelect1RowPrepareAbstract rozšiřuje BenchmarkInit { private String request ="SELECT CAST(? jako znaková sada utf8)"; public String select1RowPrepare(Connection connection, MyState state) vyvolá SQLException { try (PreparedStatement PrepareStatement =connection.prepareStatement(request)) { PrepareStatement.setString(1, state.insertData[state.counter++]); try (ResultSet rs =readyStatement.executeQuery()) { rs.next(); return rs.getString(1); } } }}

Testy využívající dotazy INSERT se odesílají do BLACKHOLE enginu se zakázaným binárním protokolem, aby se zabránilo IO a závislosti na výkonu úložiště. To umožňuje dosáhnout stabilnějších výsledků.
(Bez použití enginu blackhole a deaktivace binárního protokolu by se časy provádění lišily až o 10 %).

Benchmark byl proveden na databázích MariaDB Server 10.1.17 a MySQL Community Server 5.7.13. Následující dokument ukazuje výsledky pomocí 3 ovladačů se serverem MariaDB 10.1.17. Kompletní výsledky včetně těch s MySQL Serverem 5.7.13 naleznete v odkazu v dolní části dokumentu.

ŽIVOTNÍ PROSTŘEDÍ

Spuštění (klient a server) se provádí na jediném serveru droplet na digitalocean.com pomocí následujících parametrů:

  • Java(TM) SE Runtime Environment (sestavení 1.8.0_101-b13) 64 bitů (skutečně poslední verze při spuštění tohoto benchmarku)
  • Ubuntu 16.04 64bits
  • 512 MB paměti
  • 1 CPU
  • databáze MariaDB “10.1.17-MariaDB”, MySQL Community Server sestavení “5.7.15-0ubuntu0.16.04.1”
    pomocí výchozích konfiguračních souborů a těchto dalších možností:

    • max_allowed_packet =40 milionů #exchange packet může mít až 40 MB
    • character-set-server =utf8 #pro použití UTF-8 jako výchozí
    • collation-server =utf8_unicode_ci #pro použití UTF-8 jako výchozí

Když je uvedeno „vzdálené“, srovnávací testy se spouštějí se samostatným klientem a serverem na 2 identických hostitelích ve stejném datovém centru s průměrným pingem 0,350 ms.

VZORKOVÉ VYSVĚTLENÍ VÝSLEDKŮ

Chyba srovnávacího skóre JednotkyBenchmarkSelect1RowPrepareText.mariadb 62,715 ± 2,402 µs/opBenchmarkSelect1RowPrepareText.mysql 88,670 ± 3,505 µs/opBenchmark>7µs/opBenchmark2le±.2R. 

To znamená, že tento jednoduchý dotaz bude trvat průměrně 62,715 mikrosekund s použitím ovladače MariaDB s odchylkou ± 2,402 mikrosekund pro 99,9 % dotazů.
Stejné provedení s použitím ovladače drizzle bude trvat průměrně 88,670 mikrosekund a 78,672 mikrosekund pomocí konektoru MySQL (menší doba provádění, tím lépe).

Zobrazená procenta jsou nastavena podle prvního výsledku mariadb jako referenční (100 %), což umožňuje snadné porovnání ostatních výsledků.

POROVNÁNÍ VÝKONU

Benchmark otestuje výkon 3 hlavních různých chování pomocí stejné lokální databáze (stejný server) a vzdálené databáze (jiný identický server) ve stejném datovém centru s průměrným pingem 0,450 ms

Různá chování:

Textový protokol

To odpovídá možnosti useServerPrepStmts disabled.
Dotazy se odesílají přímo na server s výměnou vyčištěných parametrů na straně klienta.
Data jsou odesílána jako text. Příklad:Časové razítko bude odesláno jako text „1970-01-01 00:00:00.000500“ s použitím 26 bajtů

Binární protokol

To odpovídá možnosti useServerPrepStmts povolené (výchozí implementace v ovladači MariaDB).
Data jsou odesílána v binárním formátu. Příklad časového razítka „1970-01-01 00:00:00.000500“ bude odeslán pomocí 11 bajtů.

Pro jeden dotaz existují až 3 výměny se serverem:

  1. PŘEPRAVIT – Připraví výpis k provedení.
  2. EXECUTE – Odeslat parametry
  3. DEALLOCATE PREPARE – Uvolní připravený příkaz.

Další informace naleznete v části Příprava dokumentace serveru.

Výsledky PREPARE se ukládají do mezipaměti na straně ovladače (výchozí velikost 250). Pokud je Prepare již v mezipaměti, PREPARE se neprovede, DEALLOCATE se provede pouze tehdy, když se PREPARE již nepoužívá a není v mezipaměti. To znamená, že některé provedení dotazu bude mít 3 zpáteční cesty, ale některé bude mít pouze jeden zpáteční, přičemž se odešle identifikátor a parametry PREPARE.

Přepsat

To odpovídá možnosti rewriteBatchedStatements povolené.
Rewrite používá textový protokol a týká se pouze dávek. Ovladač přepíše dotaz pro rychlejší výsledky.

Příklad:
Vložit do ab (i) hodnoty (?) s hodnotami první dávky [1] a [2] budou přepsány na
Vložit do ab (i) hodnoty (1), (2).

Pokud dotaz nelze přepsat do „multi-values“, přepsání použije multi-queries :
Insert into table(col1) values ​​(?) při duplicitní aktualizaci klíče col2=? s hodnotami [1,2] a [2,3] budou přepsány na
Insert into table(col1) values ​​(1) při aktualizaci duplicitního klíče col2=2;Insert into table(col1) values ​​(3) on duplicitní aktualizace klíče col2=4

Nevýhody této možnosti jsou:

  • ID automatického zvýšení nelze získat pomocíStatement.html#getGeneratedKeys().
  • Je povoleno více dotazů v jednom provedení. To není problém pro PreparedStatement, ale pokud aplikace používá Prohlášení, může to znamenat snížení zabezpečení (injekce SQL).

* MariaDB a MySQL mají implementována tato 3 chování, pouze protokol Drizzle.

BENCHMARK VÝSLEDKY

Výsledky ovladače MariaDB

JEDINÝ VÝBĚR DOTAZU

private String request ="SELECT CAST(? as char character set utf8)";public String select1RowPrepare(Připojení připojení, stav MyState) vyvolá výjimku SQLException { try (PreparedStatement PrepareStatement =connection.prepareStatement(request)) { PrepareStatement.setString( 1, state.insertData[state.counter++]); //náhodných 100 bajtů. try (ResultSet rs =readyStatement.executeQuery()) { rs.next(); return rs.getString(1); } }}
MÍSTNÍ DATABÁZE:BenchmarkSelect1RowPrepareHit.mariadb 58,267 ± 2,270 µs/opBenchmarkSelect1RowPrepareMiss.mariadb 118,896 ± 5,500 µs/opBenchpar450Text2µriad12±2Row.

VZDÁLENÁ DATABÁZE:BenchmarkSelect1RowPrepareHit.mariadb 394,354 ± 13,102 µs/opBenchmarkSelect1RowPrepareMiss.mariadb 709,843 ± 31,090 µs/opBench ± 31,090 µs/opText1µR2op1ma.8Select1µR2op1ma.8Select.5 

Když je výsledek PREPARE pro tento přesný dotaz již v mezipaměti (úspěšný zásah do mezipaměti), bude dotaz rychlejší (7,1 % v tomto příkladu) než pomocí textového protokolu. Kvůli dodatečnému požadavku na výměny PREPARE a DEALLOCATE je miss cache o 68,1 % pomalejší.

To zdůrazňuje výhody a nevýhody používání binárního protokolu. Cache HIT je důležitý.

JEDINÝ VKLADOVÝ DOTAZ

private String request ="INSERT INTO blackholeTable (charValue) values ​​(?)";public boolean executeOneInsertPrepare(Connection connection, String[] data) vyvolá SQLException { try (PreparedStatement PrepareStatement =connection.prepareStatement(požadavek)) { PreparedStatement(požadavek)) setString(1, data[0]); //náhodný 100bajtový návrat dat readyStatement.execute(); }}
MÍSTNÍ DATABÁZE:BenchmarkOneInsertPrepareHit.mariadb 61,298 ± 1,940 µs/opBenchmarkOneInsertPrepareMiss.mariadb 130,896 ± 6,362 µs/opBenchpareText 6µ±6 µs/preriadb.6 
VZDÁLENÁ DATABÁZE:BenchmarkOneInsertPrepareHit.mariadb 379,295 ± 17,351 µs/opBenchmarkOneInsertPrepareMiss.mariadb 802,287 ± 24,825 µs/In415preriademark1bOne5 µText ±15preriade.5.5.4 

Výsledky pro INSERTs jsou podobné výsledkům SELECTs.

BATCH:1000 INSERT QUERY

private String request ="INSERT INTO blackholeTable (charValue) values ​​(?)";public int[] executeBatch(Connection connection, String[] data) vyvolá SQLException { try (PreparedStatement PrepareStatement =connection.prepareStatement(request)) { for (int i =0; i <1000; i++) { readyStatement.setString(1, data[i]); //náhodná 100bajtová data PrepareStatement.addBatch(); } return readyStatement.executeBatch(); }}
MÍSTNÍ DATABÁZE:PrepareStatementBatch100InsertPrepareHit.mariadb 5,290 ± 0,232 ms/opPrepareStatementBatch100InsertRewrite.mariadb 0,404 ± 0,014 ms/opPrepare10mariadb 0,404 ± 0,014 ms/opPrepareStatement1Briadatb.6 ± 6 ms/opPrepareStatement1Briadatb.2. 
VZDÁLENÁ DATABÁZE:PrepareStatementBatch100InsertPrepareHit.mariadb 7,639 ± 0,476 ms/opPrepareStatementBatch100InsertRewrite.mariadb 1,164 ± 0,037 ms/opriadatbText/opPrepare101ma.3m ± 0,037 ms/opPrepare10.5ma. 

Použití binárního protokolu je zde důležitější, výsledky jsou o 13 % rychlejší než použití textového protokolu.

Přílohy se odesílají hromadně a výsledky se čtou asynchronně (což odpovídá možnostiuseBatchMultiSend). To umožňuje dosahovat vzdálených výsledků s výkonem, který není daleko od místních.

Přepis má úžasně dobrý výkon, ale nebude mít automatické zvýšení ID. Pokud nepotřebujete ID okamžitě a nepoužíváte ORM, bude toto řešení nejrychlejší. Některé ORM umožňují konfiguraci zpracovávat sekvence interně a poskytovat přírůstkové ID, ale tyto sekvence nejsou distribuovány, takže nebudou fungovat na clusterech.

POROVNÁNÍ S OSTATNÍMI OVLADAČI

VYBRAT dotaz s výsledkem na jednom řádku

BenchmarkSelect1RowPrepareHit.mariadb 58.267 ± 2.270 µs/opBenchmarkSelect1RowPrepareHit.mysql 73.789 ± 1.863 µs/opBenchmarkSelect1RowPrepareMiss.mariadb 118.896 ± 5.500 µs/opBenchmarkSelect1RowPrepareMiss.mysql 150.679 ± 4.791 µs/opBenchmarkSelect1RowPrepareText.mariadb 62.715 ± 2.402 µs/opBenchmarkSelect1RowPrepareText.mysql 88.670 ± 3.505 µs /opBenchmarkSelect1RowPrepareText.drizzle 78,672 ± 2,971 µs/opBenchmarkSelect1RowPrepareTextHA.mariadb 64,676 ± 2,192 µs/opBenchmarkSelect1RowPrepareText/1772µsql ± 

HA znamená „High Availability“ s použitím konfigurace Master-Slave
(URL připojení je „jdbc:mysql:replication://localhost:3306,localhost:3306/testj“).

Tyto výsledky jsou způsobeny mnoha různými možnostmi implementace. Zde je několik důvodů, které vysvětlují časové rozdíly:

  • Ovladač MariaDB je optimalizován pro UTF-8, což umožňuje méně vytváření pole bajtů, zabraňuje kopírování pole a spotřebovává paměť.
  • Implementace HA:Ovladače MariaDB a MySQL používají dynamickou třídu proxy v jazyce Java, která je umístěna mezi objekty Statement a sokety, což umožňuje přidat chování při přepnutí při selhání. Toto přidání bude stát režii 2 mikrosekundy na dotaz (62,715 bez toho, aby to bylo 64,676 mikrosekund).
    V implementaci MySQL jsou téměř všechny interní metody proxy, což přidává režii pro mnoho metod, které nemají nic společného s převzetím služeb při selhání. celkovou režii 50 mikrosekund na každý dotaz.

(Drizzle nemá funkci PREPARE ani HA)

„Vyberte 1000 řádků“

private String request ="select * from seq_1_to_1000"; //pomocí sekvenčního storage engineprivate ResultSet select1000Row(Connection connection) vyvolá SQLException { try (Statement statement =connection.createStatement()) { try (ResultSet rs =statement.executeQuery(request)) { while (rs.next()) { rs.getString(1); } return rs; } }
BenchmarkSelect1000Rows.mariadb 244,228 ± 7,686 µs/opBenchmarkSelect1000Rows.mysql 298,814 ± 12,143 µs/opBenchmarkSelect1000Rows.0585µs7 6.4op 

Při použití velkého množství dat se čas většinou stráví čtením ze soketu a uložením výsledku do paměti pro jeho odeslání zpět klientovi. Pokud by benchmark pouze spouštěl SELECT bez čtení výsledků, doba provádění MySQL a MariaDB by byla ekvivalentní. Protože cílem SELECT dotazu je mít výsledky, je ovladač MariaDB optimalizován tak, aby vracel výsledky (nevytvářel se bajtová pole).

„Vložit 1000 řádků“

LOCAL DATABASE:PrepareStatementBatch100InsertPrepareHit.mariadb 5.290 ± 0.232 ms/opPrepareStatementBatch100InsertPrepareHit.mysql 9.015 ± 0.440 ms/opPrepareStatementBatch100InsertRewrite.mariadb 0.404 ± 0.014 ms/opPrepareStatementBatch100InsertRewrite.mysql 0.592 ± 0.016 ms/opPrepareStatementBatch100InsertText.mariadb 6.081 ± 0.254 ms/opPrepareStatementBatch100InsertText.mysql 7.932 ± 0,293 ms/opPrepareStatementBatch100InsertText.drizzle 7,314 ± 0,205 ms/op
DISTANT DATABASE:PrepareStatementBatch100InsertPrepareHit.mariadb 7.639 ± 0.476 ms/opPrepareStatementBatch100InsertPrepareHit.mysql 43.636 ± 1.408 ms/opPrepareStatementBatch100InsertRewrite.mariadb 1.164 ± 0.037 ms/opPrepareStatementBatch100InsertRewrite.mysql 1.432 ± 0.050 ms/opPrepareStatementBatch100InsertText.mariadb 8.148 ± 0.563 ms/opPrepareStatementBatch100InsertText.mysql 43.804 ± 1,417 ms/opPrepareStatementBatch100InsertText.drizzle 38,735 ± 1,731 ms/op

Hromadné vložení MySQL a Drizzle jsou jako X INSERT:Driver odešle 1 INSERT, počká na výsledek vložení a odešle další vložení. Latence sítě mezi jednotlivými vložkami zpomalí vkládání.

Procedury obchodu

VOLÁNÍ K POSTUPU

//CREATE PROCEDURE inoutParam(INOUT p1 INT) begin set p1 =p1 + 1; endprivate String request ="{call inOutParam(?)}";private String callableStatementWithOutParameter(připojení připojení, stav MyState) vyvolá výjimku SQL { try (CallableStatement uloženProc =connection.prepareCall(požadavek)) { uloženéProc.setInt(1) stav.funkceV; //2 uloženoProc.registerOutParameter(1, Types.INTEGER); uloženoProc.execute(); return uloženo.getString(1); }}
BenchmarkCallableStatementWithOutParameter.mariadb 88,572 ± 4,263 µs/opBenchmarkCallableStatementWithOutParameter.mysql 714,108 ± 44,390 µs/op

Implementace MySQL a MariaDB se zcela liší. Ovladač Mysql použije mnoho skrytých dotazů k získání výstupního výsledku:

  • SHOW CREATE PROCEDURE testj.inoutParam k identifikaci parametrů IN a OUT
  • SET @com_mysql_jdbc_outparam_p1 = 1 k odesílání dat podle parametrů IN / OUT
  • CALL testj.inoutParam(@com_mysql_jdbc_outparam_p1) postup volání
  • SELECT @com_mysql_jdbc_outparam_p1 číst výstupní výsledek

Implementace MariaDB je přímočará pomocí schopnosti mít parametr OUT v odpovědi serveru bez jakýchkoli dalších dotazů. (To je hlavní důvod, proč ovladač MariaDB vyžaduje server MariaDB/MySQL verze 5.5.3 nebo novější).

ZÁVĚR

Ovladač MariaDB je otřesný!

Binární protokol má různé výhody, ale spoléhá na to, že výsledky PREPARE jsou již v mezipaměti. Pokud aplikace mají mnoho různých druhů dotazů a databáze je vzdálená, nemusí to být lepší řešení.

Přepis má úžasné výsledky pro zápis dat v dávce

Řidič se drží dobře oproti ostatním řidičům. A je toho ještě hodně, ale to je jiný příběh.

Nezpracované výsledky:

  1. s místní databází MariaDB 10.1.17, vzdálená
  2. s místní databází MySQL Community Server 5.7.15 (sestavení 5.7.15-0ubuntu0.16.04.1)

  1. C#:Předá uživatelsky definovaný typ uložené proceduře Oracle

  2. Jak vyhodnotit výraz v příkazu select v Postgresu

  3. Jak získat přístup k databázi Oracle přes síť?

  4. Při mapování sloupce PostgreSQL LTREE v režimu spánku se zobrazuje chyba