Skip to content

Instantly share code, notes, and snippets.

@jab4
Last active January 2, 2022 01:14
Show Gist options
  • Save jab4/ff251cbcd4400851dfe3fb01f1359679 to your computer and use it in GitHub Desktop.
Save jab4/ff251cbcd4400851dfe3fb01f1359679 to your computer and use it in GitHub Desktop.
PHP-MariaDB DB Engine INSERT Performance comparison (2022-01-01) (Ubuntu 21.10)

Just another MariaDB performance test script

System: ESXi Virtual Machine

  • Ubuntu 21.10 Impish (Linux 5.13.0-22-generic)
  • File system: btrfs
  • CPU: Intel(R) Xeon(R) CPU E5-2667 v4 @ 3.20GHz (family: 0x6, model: 0x4f, stepping: 0x1)
  • under vmware ESXi 7.0 (with VMware PVSCSI rev 2 storage controller)
  • CPU cores: 8
  • VM RAM: 8 GB
  • PHP 8.1.1 (8.1.1-2+ubuntu21.10.1+deb.sury.org+1)
  • MariaDB 10.6 (1:10.6.5+maria~impish)
  • PHP with mysqli extension on localhost via UNIX socket
  • Storage: HPE RAID 6 with 10k RPM HDDs and some SSDs for caching

Results/Output of the script:

# nice php mysql_perf.php 
Testing engine         aria with 10000 rows of bogus data in database fail2ban...
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Testing engine         aria: 10,000 rows INSERTed in  0:59 ~ (59.70 s)

------------
Testing engine       myisam with 10000 rows of bogus data in database fail2ban...
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Testing engine       myisam: 10,000 rows INSERTed in  0:02 ~ (2.13 s)

------------
Testing engine       innodb with 10000 rows of bogus data in database fail2ban...
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Testing engine       innodb: 10,000 rows INSERTed in  0:55 ~ (55.25 s)

------------
Array
(
    [aria] => 59.701476812363
    [myisam] => 2.1279759407043
    [innodb] => 55.251499891281
)

Test data

  • Bogus datetime, incremented from the start point (10000 hours ago) by almost an hour on every run
  • Bogus md5-ish strings varying from 32 to 254 chars in length, ASCII only
  • Bogus DATE, derived from first datetime field

Test data comment

  • Yes, the test data is 100% synthetic fakery
  • Yes, the table is not wide, 3 columns only
  • Yes, a single data set is not very large
  • Yes, there are indexes, the DATETIME column as primary key is its own index, and there are 2 other indexes for the other two respective columns.
  • Yes, the use of some PHP built-ins for generating the fake data may use some CPU cycles compared to static data.
  • And yes, the (in this case) totally superfluoius use of real_escape_string adds extra load on the database, as well as the MySQL built-ins regarding date and time conversions.
  • But I think this is quite reasonable and reflects some aspects of real-world RDBMS use.

Result comments

  • I've run this 3 times, your mileage may vary.
  • A little disappointed of ARIA performance.
  • Not surprised by InnoDB performance, considering the transactional nature of the engine and intrinsic slowness of its index maintenance
  • Absolutely not surprised by MyISAM performance. Got regular backups running?
  • Choose your table engines wisely.
  • Recommendation? It depends:
    • Write-intensive table?
    • How important is your data?
    • Need transaction safety?
  • How are your results?

The test script

Forgive me for some hangover hickups, abstraction functions and running things as root on my system :-)

<?php
if (php_sapi_name() <> 'cli') {
    printf("This program requires cli.\n");
    exit(1);
}
mysql_perf::test();
class mysql_perf {
    const db_username = 'root'; # TODO: set to your username
    const db_password = 'qwh7t5oa2ms69ebv';   # TODO: set to your password
    const db_database = 'demo'; # TODO: set to your password
    const eng = ['aria', 'myisam', 'innodb'];
    /** @var mysqli */
    static $dbh;
    static function test() {
        $timing = [];
        $rowCount = 10000;
        $dotPrint = 100;
        foreach (self::eng AS $eng) {
            $table = "test_$eng";
            self::query("DROP TABLE IF EXISTS $table");
            self::createTable($eng);
            $startTime = strtotime("$rowCount hours ago");
            printf("Testing engine %8s with %d rows of bogus data in database %s...\n", $eng, $rowCount, self::db_database);
            for ($i = 0; $i < $rowCount; $i++) {
                if ($i % $dotPrint == 0) print ".";
            }
            print "\r";
            $µ = microtime(true);
            for ($i = 0; $i < $rowCount; $i++) {
                $time = $startTime + ($i*3240);
                $text = str_repeat(md5($time), 8);
                $text = self::sql_escape(substr($text, 0, rand(32, 254)));
                self::query("INSERT IGNORE INTO $table SET
                    `dt` = FROM_UNIXTIME($time),
                    `tx` = '$text',
                    `dd` = DATE(FROM_UNIXTIME($time))
                ");
                if ($i % $dotPrint == 0) print "+";
            }
            print("\n");
            $µ = microtime(true) - $µ;
            $tm = floor($µ / 60);
            $ts = floor($µ % 60);
            printf("Testing engine %8s: %s rows INSERTed in %2d:%02d ~ (%1.2F s)\n\n------------\n", $eng, number_format($rowCount), $tm, $ts, $µ);
            $timing[$eng] = $µ;
        }
        print json_encode([
            'Datetime' => gmdate('c'),
            'Sysinfo' => self::getSystemInfo(),
            'SqlEngineTestRowCount' => $rowCount,
            'SqlEngineTimingResults' => $timing,
        ], JSON_PRETTY_PRINT^JSON_INVALID_UTF8_SUBSTITUTE^JSON_UNESCAPED_SLASHES);
        printf("\n");
    }
    static private function __initDB() {
        if (!empty(self::$dbh)) {
            return;
        }
        self::$dbh = mysqli_connect(null, self::db_username, self::db_password, self::db_database);
        self::$dbh->set_charset('utf8mb4');
        self::$dbh->query('SET interactive_timeout=15');
    }
    static function query($query) {
        self::__initDB();
        return self::$dbh->query($query);
    }
    static function sql_escape($string) {
        self::__initDB();
        return self::$dbh->real_escape_string($string);
    }
    static function createTable($engine) {
        $sql = "            CREATE TABLE `test_$engine` (
                `dt` DATETIME NOT NULL,
                `tx` CHAR(254) CHARACTER SET ascii COLLATE ascii_bin,
                `dd` DATE,
                KEY `tx` (`tx`) USING BTREE,
                KEY `dd` (`dd`) USING BTREE,                PRIMARY KEY (`dt`)
            ) ENGINE=$engine;
        ";
        self::query($sql);
    }
    static function getSystemInfo() {
        $sysInfo = explode("\n", trim(`dmesg | egrep "boot: CPU[[:digit:]]: |MHz [pP]rocessor| (DMI|Memory): |smp: Brought up"`));
        $sysInfo = array_map(function($line) { return trim(preg_split('%\]\s+%', $line, 2)[1]); }, $sysInfo);
        return [
            'Kernel' => trim(`uname -srv`),
            'System' => $sysInfo,
            'MySQL' => self::$dbh->get_server_info(),
            'PHP' => PHP_VERSION,
        ];
    }
}

License notice: This is Public Domain — do whatever you please with this.

@jab4
Copy link
Author

jab4 commented Jan 2, 2022

Updated above script to add sysinfo output.

Output from another Ubuntu 21.04 VM (Virtualbox) on another host system (Windows 10, uptime 261 days cough) with a simple no-redundancy SATA JBOD disk configuration:

Testing engine     aria with 10000 rows of bogus data in database demo...
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Testing engine     aria: 10,000 rows INSERTed in  0:10 ~ (10.11 s)

------------
Testing engine   myisam with 10000 rows of bogus data in database demo...
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Testing engine   myisam: 10,000 rows INSERTed in  0:02 ~ (2.88 s)

------------
Testing engine   innodb with 10000 rows of bogus data in database demo...
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Testing engine   innodb: 10,000 rows INSERTed in  0:14 ~ (14.55 s)

------------
{
    "Datetime": "2022-01-02T01:07:55+00:00",
    "Sysinfo": {
        "Kernel": "Linux 5.11.0-41-generic #45-Ubuntu SMP Fri Nov 5 11:37:01 UTC 2021",
        "System": [
            "DMI: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006",
            "tsc: Detected 3693.234 MHz processor",
            "Memory: 3948292K/4193848K available (16393K kernel code, 3480K rwdata, 10480K rodata, 2696K init, 5964K bss, 245296K reserved, 0K cma-reserved)",
            "smpboot: CPU0: AMD Ryzen 7 2700X Eight-Core Processor (family: 0x17, model: 0x8, stepping: 0x2)",
            "smp: Brought up 1 node, 8 CPUs"
        ],
        "MySQL": "5.5.5-10.5.13-MariaDB-0ubuntu0.21.04.1",
        "PHP": "7.4.16"
    },
    "SqlEngineTestRowCount": 10000,
    "SqlEngineTimingResults": {
        "aria": 10.106056928634644,
        "myisam": 2.878734827041626,
        "innodb": 14.554396152496338
    }
}

MyISAM still is a clear INSERT winner, but the InnoDB and ARIA tests clearly show that the first system on ESXi-basis has some write performance issues itself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment