Benchmark MemCP vs. MariaDB on Wordpress

From MemCP
Jump to navigation Jump to search


Benchmark MemCP vs. MariaDB on Wordpress

WordPress does more than fetch individual posts. Category pages, comment counters, search, archive lists, and plugin metadata queries repeatedly join and aggregate data. These are the places where a different database engine can make a noticeable difference.

We compared MariaDB, MemCP, and MemCP with JIT using seven SQL queries captured from a WordPress installation. On the tested master revision, JIT-enabled MemCP completed the comment-count query 25.5 times faster and the archive query 4.8 times faster than MariaDB. A simple option lookup was effectively tied. Two small metadata queries still favored MariaDB.

For administrators, the takeaway is specific: MemCP offers substantial potential for recurring aggregates, but the right migration decision depends on your site's query mix, correctness, and cache behavior—not one headline multiplier.

Status of this measurement — 8 September 2026

The tested master revision has two known correctness issues exposed by this fixture: a blob-reference decoding problem and lost collation in the grouped taxonomy plan. Search also returns an incorrect total count. The affected timings below are diagnostic only, not accepted speedup claims. This is a development benchmark supporting a staging evaluation, not a recommendation to replace a production WordPress database with this revision.

The results at a glance

The following values are warm end-to-end database latency: sending SQL over an established TCP/MySQL connection and receiving the complete result. For the search and SEO queries, the time also includes a subsequent SELECT FOUND_ROWS() on the same connection.

Lower is better. The comparison column is MariaDB versus MemCP JIT—not JIT versus vanilla.

WordPress workload MariaDB MemCP MemCP + JIT MemCP JIT compared with MariaDB Result check
Option lookup (siteurl) 0.082 ms 0.116 ms 0.081 ms Effectively tied; approximately 1% lower latency Same single row
Plugin metadata join with LIMIT 0.141 ms 0.211 ms 0.200 ms 41.9% higher latency Same empty result
Taxonomy join and DISTINCT 0.222 ms 0.222 ms 0.179 ms Not scored: ordering differs Same 15 rows, different order
Comment COUNT with exclusion join 4.053 ms 0.173 ms 0.159 ms 25.5× faster; 96.1% lower latency Same aggregate result
WordPress search and total count 31.457 ms 2.192 ms 1.766 ms Not scored: total count differs Same first 10 rows; total 82 instead of 83
SEO metadata CAST/range join 0.177 ms 0.225 ms 0.198 ms 11.8% higher latency Same empty result and total of zero
DISTINCT year/month archive 0.666 ms 0.158 ms 0.138 ms 4.8× faster; 79.2% lower latency Same 10 ordered rows

The empty metadata results are intentional disclosures, not successful-hit performance tests. They measure how quickly each engine establishes that there are no matching records in this snapshot. They do not establish performance for populated plugin result sets.

There is no combined “WordPress speedup” score. The frequency of these queries differs between sites, and a correctness failure must not be averaged into a favorable result.

What this means for a WordPress administrator

Look for expensive repeated database work

A site dominated by indexed point lookups has less to gain from the results here: the option lookup took about 0.08 ms in both MariaDB and JIT-enabled MemCP. A site spending database time on counts, joins, and archive aggregates has a more promising starting point.

For example, the measured comment-count query saves approximately 3.89 ms per execution. That can matter if the query is frequent or occurs repeatedly while rendering an uncached request. It does not imply that the entire PHP request becomes 25 times faster.

Use your own slow-query trace or query-monitoring output to identify the statements that dominate database time. Include frontend pages, administration screens, searches, and scheduled plugin work.

Understand what is warm

MemCP can reuse compiled query plans and incrementally maintained relational structures such as group caches and prejoins. These structures help avoid repeating a join or aggregate from scratch.

A warm read benchmark benefits from that reuse. It does not measure the complete cost of maintaining those structures under writes. New comments, imports, metadata updates, and bulk edits therefore belong in a separate staging test.

JIT is another part of execution: eligible code is compiled to native instructions. It is not permission to change SQL results, and it does not make every query faster. The vanilla column shows that much of the aggregate advantage is already present without JIT.

Budget for the first request

Fast warm responses do not imply that the first request is equally fast. In this run, selected first-query and warm values were:

Query MemCP first query MemCP + JIT first query MemCP + JIT warm median
Plugin metadata join 42.3 ms 33.2 ms 0.200 ms
Comment COUNT 52.1 ms 66.2 ms 0.159 ms
WordPress search — correctness issue 1,957.7 ms 2,553.0 ms 1.766 ms
Archive 13,652.3 ms 14,560.0 ms 0.138 ms

Preparation can also occur after the first execution. During the 20 warmup requests, the plugin metadata query had an approximately 650 ms outlier in each MemCP mode; the search had approximately 580 ms outliers.

These are observed first-query latencies after restarting each MemCP process, not a controlled empty-cache comparison: persisted structures and operating-system caches were retained, and vanilla ran before JIT against the same data directory. Server startup itself is not included in these values.

For a migration rehearsal, measure first requests after restart, cache eviction, and representative writes separately. Do not use the warm table to set cold-start service-level expectations.

A more useful WordPress fixture

The queries come from a WordPress installation using common plugins, including WooCommerce, Elementor, Yoast SEO, Advanced Custom Fields, and Contact Form 7. No plugin receives a special place in the scoring; the seven statements cover distinct kinds of database work.

The measured version-2 queryset fixture contains these seven tables—not the complete live WordPress installation:

Table Rows
wp_posts 22,063, including 20,000 revisions
wp_postmeta 14,013
wp_comments 6,001
wp_options 503
wp_terms 175
wp_term_taxonomy 175
wp_term_relationships 7,701

Version 1 repeated essentially the same search-bearing paragraph in every generated article. Version 2 replaces that with 2,000 different titles, excerpts, and article bodies across 16 topics. Article bodies range from 396 to 6,996 bytes, with a median of 1,764 bytes. Revisions retain their parent document's content with an editorial change; low-cardinality fields such as status and categories still repeat naturally.

The generator deliberately provides several search frequencies over the 2,000 generated articles:

  • nightjar: 10 matches, or 0.5%;
  • realistic: 80 matches, or 4%;
  • performance: 240 matches, or 12%;
  • quasarless: no matches.

These are corpus checks, not four separately timed search workloads. The captured search query uses realistic. Its SQL also considers pages and other post types and applies additional predicates, so its complete MariaDB total is 83 rather than 80.

This is a controlled synthetic dataset with real captured query shapes. It is not evidence of performance at millions of posts or under concurrent production traffic. The gains on counts and archives justify testing larger datasets; they do not replace that test.

Correctness before speed

Results were compared across engines, including FOUND_ROWS() where applicable. Five query shapes agreed; two did not.

Taxonomy ordering

Both databases expose wp_terms.name with utf8mb4_unicode_520_ci. A direct ordered scan agrees, but the full DISTINCT/join plan loses that collation at its grouped sort. For example, MemCP places Uncategorized before lower-case tag names.

This is not an unspecified tie order. It is a correctness issue, and the taxonomy timing is excluded from speedup claims.

Blob content and search totals

Full table contents matched checksums immediately after import. After MemCP compaction, 33 long post-content values were observed as 32-byte blob hashes instead of their text. A hash beginning with ! collides with the legacy escaped-string encoding.

For one affected post, MariaDB reports a text length of 5,327 bytes and MemCP reports 32. The search's first ten rows agree, but MemCP reports 82 total matches versus MariaDB's 83. Consequently the search timing is also excluded from accepted speedup claims.

These findings must be resolved and the affected workloads revalidated before using this revision for migration. No query was removed from the table to conceal them. All 21 measurements completed without a process crash.

How the comparison was run

Item Configuration
MemCP source Master ce26bfb3d, including the merged Q1/Q3 planner improvements
Date 8 September 2026
MariaDB 10.11.14; query cache disabled; InnoDB buffer pool 128 MiB
MemCP builds Identical source, both built with the patched Go 1.27.0 toolchain; GOEXPERIMENT empty versus GOEXPERIMENT=jit
Host AMD Ryzen 9 7900X3D, 12 cores / 24 logical CPUs; approximately 62 GiB RAM
Client Python/PyMySQL over local TCP; established connections, autocommit
Sampling 20 warmup executions, then 11 batches of 100 executions per query and engine
Reported statistic Median of the 11 batch means, in milliseconds per query or query/FOUND_ROWS pair
Execution order MariaDB, MemCP vanilla, MemCP JIT
Run duration Approximately 93 seconds, excluding builds, fixture import, and investigation

The host was shared with development work and was not isolated for benchmarking. Small percentage differences should not be overinterpreted. The results are not a memory-budget-matched or concurrency-throughput comparison.

The query-plan cache and normal execution behavior remained enabled. We did not substitute hand-written plans or force a special prejoin before timing. The setup contains no application-level page-cache measurement: this is database latency, not HTTP page-render time.

The measurements are specific to this master snapshot and fixture. Earlier version-1 numbers should not be mixed with this table or used to calculate an improvement attributable solely to a planner patch.

A practical staging checklist

Before deciding whether MemCP will speed up your WordPress installation:

  1. Capture your workload. Include expensive frontend queries, admin pages, search, and the plugins your site actually uses.
  2. Use one consistent data snapshot. Preserve IDs, relationships, text, and collations. Compare contents after import and after compression/restart—not just table row counts.
  3. Check complete results. Validate ordering, pagination, NULL behavior, aggregates, and total counts, including FOUND_ROWS().
  4. Separate first use from steady state. Record startup/cache-build spikes, warm medians, and tail latency.
  5. Exercise writes and concurrency. Test comments, edits, imports, plugin jobs, cache maintenance, and recovery. This read-only query benchmark does not establish their cost or compatibility.
  6. Measure whole requests too. PHP, plugin execution, network requests, and page caching can dominate total page time even when SQL becomes faster.
  7. Keep production unchanged until validation passes. Retain your MariaDB deployment and a tested backup/rollback path during evaluation. The known correctness issues above must be closed first.

MemCP's strongest result here is the reduction of recurring aggregate work from milliseconds to a fraction of a millisecond. For WordPress administrators, that is a concrete reason to evaluate it—but equivalent results and predictable operations remain the entry requirements for any speed claim.