Sidebar

Main Menu Mobile

  • Home
  • Blog(s)
    • Marco's Blog
  • Technical Tips
    • MySQL
      • Store Procedure
      • Performance and tuning
      • Architecture and design
      • NDB Cluster
      • NDB Connectors
      • Perl Scripts
      • MySQL not on feed
    • Applications ...
    • Windows System
    • DRBD
    • How To ...
  • Never Forget
    • Environment
  • Search
TusaCentral
  • Home
  • Blog(s)
    • Marco's Blog
  • Technical Tips
    • MySQL
      • Store Procedure
      • Performance and tuning
      • Architecture and design
      • NDB Cluster
      • NDB Connectors
      • Perl Scripts
      • MySQL not on feed
    • Applications ...
    • Windows System
    • DRBD
    • How To ...
  • Never Forget
    • Environment
  • Search

Group Replication VS Percona XtraDB Cluster: The True Cost of Consistency

Details
Marco Tusa
MySQL
12 June 2026

Overview

When building high-availability MySQL environments, the choice between MySQL Group Replication (GR) and Percona XtraDB Cluster (PXC) often comes down to how they handle the eternal database dilemma: data consistency versus performance.       dolphin vs goath small

While both provide "synchronous-like" replication, they approach the problem of stale reads—reading data that has been committed on one node but not yet applied on another—in distinct ways. Understanding these differences, and the performance penalties associated with fixing them, is critical for any production environment.

Technology Overviews

MySQL Group Replication (GR)

Group Replication is the native, albeit more recent, high-availability solution built by Oracle for MySQL. It is based on a distributed state machine architecture and uses the Paxos consensus protocol.

  • Mechanism: When a transaction is committed, it is sent to all group members. The members must agree (consensus) on the order of transactions. Once a majority agrees, the transaction is "certified" and committed on the originator.
  • Replication Type: Virtually synchronous. The consensus ensures the data is received and ordered across nodes, but the actual applying of the data to the database happens asynchronously in the background.

Percona XtraDB Cluster (PXC)

PXC is an open-source enterprise solution based on Percona Server for MySQL and the Galera Replication library, which is the first and most mature virtually synchronous solution for MySQL.

  • Mechanism: When a node commits a transaction, it sends it to all other members of the Primary component (active group). All nodes must certify the transaction (check for conflicts), this is done on each node in the cluster, including the node that originates the write-set, before the originating node can finalize the commit.
  • Replication Type: Strictly synchronous (up to the certification level), asynchronous afterward. If the certification test fails, the node drops the write-set and the cluster rolls back the original transaction. If the test succeeds, however, the transaction commits and the write-set is applied to the rest of the cluster.

The Battle Against "Stale Reads": Why It Matters

The most critical distinction for developers is whether a SELECT query on Node B will immediately see the INSERT just performed on Node A.

In a distributed system, there is a microsecond-to-millisecond gap between a transaction being globally ordered (everyone knows it happened) and being locally applied (the data is physically readable in the table). Reading executed on a secondary during this gap results in a stale read.

Why is avoiding stale reads so critical?

While a stale read might just mean a user temporarily sees their old profile picture after updating it, in many business cases, it breaks the application's core logic:

  1. Financial Transactions: A user deposits $100 on the Primary node and immediately refreshes their balance page, which reads from a Replica. If the read is stale, the balance hasn't updated. The user panics, thinking their money is lost.
  2. E-commerce & Inventory: A customer buys the last item in stock. The next user immediately loads the product page. A stale read tells the second user the item is still available, leading to a cancelled order and a frustrated customer.
  3. Security & Access: A user changes their password or updates a critical permission. If the next authentication request hits a node lagging by just a fraction of a second, their valid login might be rejected, or a revoked session might still be active.

To prevent these scenarios, we must tell the database to enforce strict consistency. But how do GR and PXC handle this, and what does it cost?

Consistency Controls Comparison

Both Group Replication and Percona XtraDB Cluster provide built-in mechanisms to enforce consistency and eliminate stale reads when your application demands it. However, they approach this problem using entirely different variables and distinct levels of granularity. The table below breaks down the specific controls each technology offers, highlighting exactly what it takes to force a node to serve fresh data.

FeatureMySQL Group ReplicationPercona XtraDB Cluster
Default Behavior Reads on secondaries may be stale because the applier thread might be lagging after consensus. Reads on secondaries may be stale due to asynchronous background applying.
Stale Read Fix Uses the group_replication_consistency variable. Uses the wsrep-sync-wait variable.
Consistency Levels Offers EVENTUAL, BEFORE, AFTER, and BEFORE_AND_AFTER. Offers granular levels from 0 (default, no checks) up to 7 (checks on all READ, UPDATE, DELETE, INSERT, and REPLACE statements).
The Fix Setting to AFTER ensures the next read is fresh. Setting to 7 ensures we have a comparable scenario with GR. However in PXC setting wsrep_sync_wait = 1 will be enough to avoid stale reads.

The True Cost of Being Consistent

If we know stale reads are bad, why don't we just enforce strict consistency everywhere? 

An image can help to understand:

dirty comparative2

Because in distributed databases, consistency is incredibly expensive. To test this, we used a 3-node internal lab environment to run a Sysbench-based TPC-C derivative test (50/50 read/write split, running for 600 seconds, scaling from 1 to 1024 threads).

You can find the detailed machine specifications here. The benchmarks were executed using a TPC-C derivative test based on sysbench. Finally—and crucially—you can review the configuration files used for the tests. I maintained the same baseline MySQL configuration across the board, only adjusting the parameters specific to each replication technology.

 

Scenario 1: Default (Relaxed) Consistency

(GR = EVENTUAL, PXC = wsrep-sync-wait 0)

I want to remind, that MySQL CE and Percona Server are running using Group Replication, while PXC is using galera.

With default settings, both systems allow stale reads.

CHAOS tpcc PXC VS PS eventual run tpcc ReadCommitted

CHAOS tpcc PXC VS PS eventual run tpcc RepeatableRead

Both technologies scales well up to 128 threads:

  • Group Replication performs exceptionally well, handling up to 15K operations/sec before dropping off after 128 threads.
  • PXC (Galera) is slightly less efficient at peak but scales very nicely and predictably.

At this level, the lag between the moment of commit and the moment the server returns the answer is minimal. But we are entirely exposed to stale reads.

Scenario 2: Enforced Consistency (The Cost)

(GR = AFTER, PXC = wsrep-sync-wait 7)

When we configure the servers to prevent stale reads, the systems must wait for transactions to be fully applied before returning a read. This is where the architectural differences become glaringly apparent:

CHAOS tpcc PXC VS PS after run tpcc ReadCommitted

CHAOS tpcc PXC VS PS after run tpcc RepeatableRead

  • PXC (Galera): Performance drops but not too much from a peak of ~9K ops/sec (in the previous test)  to roughly ~8.5K ops/sec. This is a hit but not huge and the database remains highly functional and stable.
  • Group Replication: Performance catastrophically drops from ~15K ops/sec (in the previous test) to a staggering ~3.8K ops/sec.

This is the crucial takeaway

Enforcing strict consistency in Group Replication results in a massive ~75% performance penalty. The latency between the commit and the server response increases significantly compared to PXC. 

The intermediate way

There is another approach which is to inject the higher consistency only when it is really needed.

The Solution: Session-Level Consistency You do not need, and should not use, full consistency at the global level for general cases. Instead, force consistency only when and where it is critical.

While for Group Replication there is no support for SQL injection hints like SELECT /*+ SET_VAR(...) */, you can enforce this at the session level right before a critical read:

SET SESSION group_replication_consistency = 'AFTER';
-- OR for PXC:
SET SESSION wsrep_sync_wait = 7; 
 

To note that  PXC offers more flexibility and you can use hints:

select /*+ SET_VAR(wsrep_sync_wait=7) */ @@session.wsrep_sync_wait ,@@global.wsrep_sync_wait;
+---------------------------+--------------------------+
| @@session.wsrep_sync_wait | @@global.wsrep_sync_wait |
+---------------------------+--------------------------+
|                         7 |                        0 |
+---------------------------+--------------------------+
   

By isolating these variables to specific sessions (like the immediate redirect after a password change or a checkout process), you ensure data integrity exactly where the business requires it, while allowing the rest of your application to enjoy the high-speed performance of relaxed consistency. 

CHAOS tpcc PXC VS PS partial run tpcc ReadCommitted

CHAOS tpcc PXC VS PS partial run tpcc RepeatableRead

PXC: The performance drop is minimal and the solution is able to provide a consistent delivery with nice scalability up to 256 threads.

Group Replication: The solution suffers from a significant drop, not as if we set the AFTER condition at global level, but still we see a drop of ~52%. 

Comparing the two solutions we can see that PXC is able to deal with the additional requested consistency better. 

 

Additional differences

But these are not the only differences we can immediately see. Performing a comparison about resources utilization, we can see that while both solutions move the same amount of data as IO operations:

pxc vs gr disk util

 

pxc vs gr memory used

Yes, for exactly the same load and traffic Group Replication consumes 8GB more than PXC, which in this environment represents 26% memory more, over total available.

pxc vs gr cpu

Cost that is reflected also as CPU utilization.

 

Conclusion: How to Survive the Cost

How impactful is enforcing strict consistency at a global level in a production environment? Massively. If you blindly enforce strict consistency globally without understanding your architecture, you will decimate your database throughput. Here is the reality of how the two solutions handle that tax:

  • The Group Replication Reality: By default (using EVENTUAL consistency), MySQL Group Replication behaves essentially as semi-synchronous replication paired with an automated topology manager (see The Failover Brownout: Rethinking High Availability in MySQL Group Replication). The Primary is allowed to forge ahead and serve traffic even if the Secondaries are lagging significantly behind. The moment you demand strict consistency, the Primary is violently tethered back to the rest of the cluster, and its performance drops off a cliff as it waits for the slowest node.
  • The PXC Advantage: Percona XtraDB Cluster (PXC) absorbs the "consistency penalty" much more gracefully. While varying consistency levels exist in PXC, adjusting them does not cause the same dramatic throughput shock seen in MGR. This is because PXC enforces a virtually synchronous, high-consistency baseline from the start. It simply does not allow the node receiving writes to deviate too far from the rest of the cluster. You pay a baseline performance tax upfront, but in exchange, you get guaranteed, ironclad High Availability out of the box.

The Final Verdict Modifying consistency values at the global server level should only be done after rigorous load testing and a complete understanding of the performance tax you are about to pay.

Ultimately, it comes down to choosing the right tool for your specific SLA:

  • If your architecture demands a true, virtually synchronous solution with strict High Availability out of the box, PXC is the purpose-built engine for the job.
  • If you are looking for a highly automated, semi-synchronous solution, Group Replication delivers excellent default performance—but tuning it to mimic PXC's strict consistency will cost you heavily in throughput.
 

References

https://www.google.com/url?q=https://mariadb.com/docs/galera-cluster/galera-architecture/certification-based-replication&sa=D&source=docs&ust=1777342808813139&usg=AOvVaw3SAf2g7NO9d681ZJ0VVEMB

https://docs.percona.com/percona-xtradb-cluster/5.7/wsrep-system-index.html#wsrep_sync_wait

No comments on “Group Replication VS Percona XtraDB Cluster: The True Cost of Consistency”

MySQL Belgian Days and FOSDEM 2026: My Impressions

Details
Marco Tusa
MySQL
17 February 2026

First of all, I want to say a huge thank you to Frederic Descamps and the entire team who worked on the MySQL Belgian Days. I was thrilled to see the high number of presentations and the excellent quality across the board. We had two rooms packed with attendees, and the event was simply great. It was also incredibly productive to finally reconnect with so many people in the community face-to-face.

Presentation-wise, I was really impressed by Vitor Oliveira (Huawei) and his talk, "Beyond Linear Read-Ahead: Logical Prefetching using Primary and Secondary Indexes in InnoDB." I found the presentation and the work behind it fascinating. It perfectly explained something that I, along with several colleagues, had empirically proven in the field regarding InnoDB old pages and their impact on performance. I strongly suggest reviewing this presentation.

Another highly interesting talk, even if I feel its full power wasn't grasped by everyone in the room, was Arnaud Adant's session on MySQL Binary Log Analytics. The level of detail we can dig into and the way he handled the binlog was excellent. It was a great demonstration of how a well-known topic like the binlog can still hold a few surprises and remain highly relevant, especially when looking at real-world, large-scale scenarios.

During the Belgian Days, I also received the MySQL Legend award, which was totally unexpected for me. It was so unexpected, in fact, that after the final Rockstar nomination, I actually walked out of the room and missed Fred announcing my name! In pure Grinch style, Fred had to come out and drag me back in. I was so embarrassed here is the video of my momentary shame.

Now, what about FOSDEM? Well, FOSDEM is chaos, as we all know, and nobody expects anything less. However, this year we had a single database room for just one day. That meant trying to cram a whole universe into a single jar. As a result, the room was completely full, but the speeches were, at least for me, a bit too high-level and generic. I understand that was the intention given the constraints, but we need to keep this in mind for the future. Ultimately, I wasn't really impressed.

The day after, we had the MariaDB Day, which featured some interesting talks, specifically focusing on what is coming next for MariaDB. I had a few great discussions there and hope we will be able to collaborate when performing future tests.

The Summit for the MySQL Community

Last but not least, on Monday, February 2nd, we held the Summit for the MySQL Community. The event was an open discussion about how we, as a community, can work together to keep the MySQL ecosystem not just alive, but thriving and effective. It was an excellent meeting featuring people from AWS, Bloomberg, Booking, Canonical, WordPress, Oracle, Percona, MariaDB, and more. I don't have the full list, but it was amazing to see everyone together and willing to collaborate.

What became clear to everyone is that our scope is the same. No matter what company we come from, we want to ensure the MySQL/MariaDB/Percona/Whatever-flavor ecosystem continues to meet user needs and expands to tackle upcoming challenges. To do this, we need to focus on improving community interaction, code sharing, and evolution, without getting derailed by useless debates about who is the latest shining rockstar.

The intention is to do this together, Oracle included, assuming they take the right steps. In this regard, there is an open letter to Oracle that we are asking everyone to read; if you agree with its principles, please sign it.

Looking Forward: The Foundation and Ecosystem

Finally, I want to wish the best of luck to Fred (LeFred), who has decided to move on from Oracle and join the MariaDB Foundation, as he announced in his recent blog post. However, I also want to take a moment to answer the question he posed in that post:

"There is an initiative to create a foundation to ‘save’ MySQL, but doesn’t such a foundation already exist? There is a viable alternative for MySQL users: MariaDB. It offers more features, is ready to innovate further, and welcomes your contributions. Let’s work together!"

To answer Fred's question directly: No, that specific, overarching foundation does not quite exist yet and that is exactly what became so clear during Monday's summit. The fact that the MariaDB Foundation is there is fantastic, and we all view it as a vital piece of the larger puzzle we debated.

However, we also recognize that no single entity or fork can accomplish this broader mission alone. The goal of this new foundation initiative isn't to compete with MariaDB, but to build a unified, vendor-neutral space that lifts up the entire ecosystem.

So, let us stay focused on the greater good. Rather than trying to shift entirely into one court or the other, let's build a truly collaborative foundation where all flavors and contributors can thrive together. We have a lot of work ahead of us let's do it side by side.

One comment on “MySQL Belgian Days and FOSDEM 2026: My Impressions”

joins... joins... everywhere

Details
Marco Tusa
MySQL
16 February 2026

 

  1. Table(s) structure
  2. The Tests
  3. How to use it
  4. How to modify it
    1. Method 1. 
    2. Method 2
  5. How to help
  6. References

 

I have a curse. My curse is curiosity. 

Here in Percona I found one person that is very “dangerous” for me, and he and I also share the same first name, well almost, Marcos Albe. 

Marcos is a smart guy with a lot of ideas, and he is not shy to share them. One day we were talking about sysbench, and he mentioned to me: you know it would be nice to have a test for joins in sysbench. I wonder why we don’t have it; it will be so useful to identify regressions in that area.
You see where this is going right? He put that in my mind, luckily I was busy with other stuff and I forgot. Until one day. That day I had to take a more in-depth look at some claims about joins performance regressions. In that moment Marcos voice comes back as an echo resonating in my mind … it would be useful to identify regressions… 

That’s it. Ok let’s do it, let’s build this joins test and see how it goes, and shut Marcos up.

I used sysbench as an engine but then I diverged a lot while implementing the test in lua. My idea was to build a simple test but got trapped in the mechanism and (never ask AI) at the end I came up with 41 different tests and a quite complicated table(s) definition. 

Let’s see both together.

Table(s) structure

In the new test we have two different sets of tables, the main table and the level table. The main table name can be renamed as you like using the usual sysbench parameter table_name, the level table name is fix levelX and for now you have queries with only one level or all of them. Already planning to make this customizable but for now it is like that.  

The main table structure is as follows:

CREATE TABLE `%s%d` (
      `id` %s,
      l1_id INT,           -- Foreign key to level1.id
      l2_id INT,           -- Foreign key to level2.id
      l3_id INT,           -- Foreign key to level3.id
      l4_id INT,           -- Foreign key to level4.id
      l5_id INT,           -- Foreign key to level5.id
      -- Numeric data types
      small_number SMALLINT,
      integer_number INT,
      myvalue BIGINT,
      decimal_number DECIMAL(10, 2),
      float_number FLOAT,
      -- String data types
      char_field CHAR(10),
      varchar_field VARCHAR(255),
      color VARCHAR(50),
      continent VARCHAR(255),
      uuid VARCHAR(36) CHARACTER SET latin1,
      uuid_bin BINARY(16),
      text_field TEXT,
      -- Date and time data types
      datetime_field DATETIME,
      timestamp_field TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
      year_field YEAR,
      -- Binary data types
      binary_field BINARY(50),
      varbinary_field VARBINARY(255),
      -- Special data types
      enum_field ENUM('active', 'inactive', 'pending'),
      set_field SET('read', 'write', 'execute', 'delete'),
      -- Boolean type
      is_active BOOLEAN DEFAULT TRUE,
      -- Spatial data type (if using GIS)
      -- point_field POINT,
      -- Constraints
      UNIQUE KEY unique_varchar (uuid),
      INDEX idx_l1_id (l1_id),
      INDEX idx_l2_id (l2_id),
      INDEX idx_l3_id (l3_id),
      INDEX idx_l4_id (l4_id),
      INDEX idx_l5_id (l5_id),
      INDEX idx_date (datetime_field),
      INDEX idx_time (timestamp_field),
      INDEX idx_enum_field (enum_field),
      INDEX idx_set_field (set_field),
      INDEX idx_year_field (year_field),
      INDEX comp_attributes(continent,enum_field,set_field),
      INDEX comp_color(color,continent,enum_field,year_field)
)

As you can see the main table has many more attributes and datatypes than the simple test existing in the basic sysbench and more than my other windmills test. 

It also has several attributes with variable length, this is to be able to emulate cases where unordered pages are present, which is the common case in production. (see also https://www.tusacentral.net/joomla/index.php/mysql-blogs/186-innodb-page-merging-and-page-splitting). To achieve that you just need to generate write traffic on the main tables, this is not available yet in the test but is not difficult to implement. As such at the moment we should consider the test executed always on Ordered pages.

Level table structure:

CREATE TABLE `%s%d` (
      `id` %s,
      continent VARCHAR(45) NOT NULL,
      parent_id BIGINT,  -- For hierarchical structure if needed
      time_accessed TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
      l1_id INT,
      l2_id INT,
      l3_id INT,
      l4_id INT,
      l5_id INT,   
      record_name CHAR(36),
      record_code CHAR(5),
      record_value BIGINT,
      record_status ENUM('active', 'inactive', 'pending'),
      record_priority INT NOT NULL,
      INDEX idx_country (continent),
      INDEX idx_parent_id (parent_id),
      INDEX idx_l1_id (l1_id),
      INDEX idx_l2_id (l2_id),
      INDEX idx_l3_id (l3_id),
      INDEX idx_l4_id (l4_id),
      INDEX idx_l5_id (l5_id),
      INDEX idx_time_accessed (time_accessed),
      INDEX idx_record_status (record_status),
      INDEX idx_record_priority (record_priority),
      INDEX comp_record_continent_status_priority(continent,record_status,record_priority)

In this case the table structure is much simpler (than main) and it has only one attribute (Country) which is Variable, this to reduce the possibility to have unordered pages to the minimum.

The Tests

Now combining the tables I have built the following scenarios:

·         insert_update_delete_queries

·         inner_queries

·         left_queries

·         right_queries

Pro-Tip from Celko: Avoid RIGHT JOIN whenever possible. It is mathematically equivalent to a LEFT JOIN with the tables swapped. Using only LEFT JOIN makes your queries more readable and follows the "natural" left-to-right reading order of SQL.

·         semi_join & anti join condition_queries

·         subquery_queries

Using the above I have built the following scenarios:

  •    anti_join_left_join_pk 
  •    anti_join_not_exists_pk 
  •    conditional_join_pk 
  •    inner_subquery_multi_pk 
  •    left_subquery_multi_pk 
  •    multi_left_forcing_order 
  •    multi_left_index 
  •    multi_left_pk 
  •    multi_left_straight 
  •    multilevel_inner_forcing_order_index 
  •    multilevel_inner_index 
  •    multilevel_inner_pk 
  •    multilevel_inner_straight_index 
  •    multi_right_forcing_order 
  •    multi_right_index 
  •    multi_right_pk 
  •    multi_right_straight 
  •    right_subquery_multi_pk 
  •    semi_join_exists_pk 
  •    simple_inner_forcing_order 
  •    simple_inner_index 
  •    simple_inner_index_GB 
  •    simple_inner_pk 
  •    simple_inner_pk_GB 
  •    simple_inner_straight 
  •    simple_left_exclude 
  •    simple_left_forcing_order 
  •    simple_left_index 
  •    simple_left_index_GB 
  •    simple_left_pk 
  •    simple_left_pk_GB 
  •    simple_left_straight 
  •    simple_right_forcing_order 
  •    simple_right_index 
  •    simple_right_index_GB 
  •    simple_right_pk 
  •    simple_right_pk_GB 
  •    simple_right_straight 
  •    update_multi_inner_join_pk 
  •    update_multi_left_join_pk 
  •    update_multi_right_join_pk

Where simple means only one level of joins while multi is all the five levels. 

If you want to review them you can easily do it reviewing the file in github (https://github.com/Tusamarco/sysbench/blob/master/src/lua/joins/join_queries.lua)

Please keep in mind a couple of things:

  1. This is just a start; I do not pretend to cover all and I am open to add whatever it will be identified as useful.

  2. You are encouraged to test and modify any part of the code, query, table structure and share your changes, the more we work on this together the better it will be. 

How to use it

First clone the repo as usual, build sysbench and install it, instructions here(https://github.com/Tusamarco/sysbench/tree/master?tab=readme-ov-file#build-and-install). 

Unless you do it manually the tests in the src/lua/… will not be copy over if you want you can modify the file https://github.com/Tusamarco/sysbench/blob/master/src/lua/Makefile.am to have them installed with make install.

As usual the first step is to create and populate the schema:

sysbench /opt/sysbench/src/lua/joins/oltp_read_write.lua  --mysql-host=<ip> --mysql-port=<port> --mysql-user=<user> --mysql-password=<pw> --mysql-db=joins --db-driver=mysql  --report-interval=1  --table_name=main  --tables=15 --table_size=100000 --threads=15  prepare

This will create 15 main tables and 5 levelX tables, both with 100000 rows.

I suggest you create a schema with a decent number of rows, in general the dimension of all rows in a table should exceed the allocated memory buffer. So, if you have a 10GB Innodb buffer pool, it would be nice to have each table to be at least 15GB.

Always do a warmup, that will fill the BP with data, most likely from the last main table, but this is fine, you just want the BP to be hot. 

Once done you can run the tests. 

To evaluate the join execution, I think that the most immediate metric is the execution time. Given that when you run the test you should set –time=0 –events=X where X is the number of events you want to execute. 

How many queries will an event have? Easy, if you define it as a parameter, by default all the joins are set to 0, which means disable and you need to enable it. 

For instance if you want to execute simple_inner_pk test, you need to set --simple_inner_pk=1 where 1 is the number of occurrence, so if you set it to 1 you have one event one query, if you set --simple_inner_pk=2 you have that each event generate 2 queries… and so on. 

Given the time taken is captured for the whole test, my advice is to keep the occurrence to 1 and eventually check/test how the platform scales by concurrent threads.

To do so, you need to set the number of events and threads to the same value. 

See a full example below:

sysbench /opt/sysbench/src/lua/joins/oltp_read_write.lua  --mysql-host=<ip> --mysql-port=<port> --mysql-user=<user> --mysql-password=<pw> --mysql-db=joins --db-driver=mysql  --skip_trx=off --report-interval=1  --histogram --table_name=main  --stats_format=csv --tables=15 --table_size=1000000 --time=0 --multilevel_inner_pk=1 --events=5 –threads=5 run

This will record the time taken to execute 5 queries in parallel.

While you can enable more than one test at the same time, to me this is not useful given it will be not clear who is taking longer unless you do not keep track of that in other ways, like slow query log or performance schema.  

 

How to modify it

You want to modify the queries or table structure?

Do it! Just modify the file joins_queries.lua. There you will find the table definition for the main and level table.
The only thing to be careful of is to change the variables in the load_global_variables() to match your changes and of course you will need to modify the initialize_values_X for main and level table.

If instead you only want to change the queries you have two ways.

  1. Add your query to an already existing map 

  2. Create a new map

Method 1. 

Say you want to add a query for the left joins. Identify the left_queries = {…} map and add the query you want to add:

["my_custom_left_query"] = [[SELECT m.continent,year_field, m.enum_field, level1.record_value l1
FROM %s%u as m
LEFT JOIN level1 ON m.l1_id = level1.id and m.enum_field = '%s'
WHERE m.continent = '%s'
ORDER BY m.year_field DESC, l1 DESC
LIMIT 100;]],

Here I am not adding anything special, so I just need to add a pair of [KEY] = <SELECT> using the same attributes. 

In case you need to change the attributes, then you need to create a case in the function that fill the query. The function is: function execute_joins(join_name) in joins/oltp_common.lua. 

For instance if I want to have my custom query filtering by the attribute color in the main table, I can do:

["my_custom_left_query"] = [[SELECT m.continent,year_field, m.enum_field, level1.record_value l1
FROM %s%u as m
LEFT JOIN level1 ON m.l1_id = level1.id and m.enum_field = '%s'
WHERE m.color = '%s'
ORDER BY m.year_field DESC, l1 DESC
LIMIT 100;]],

In the function I can add a case like:


  if join_name:find("my_custom_left") then
     for i = 1, sysbench.opt[join_name] do
        local tnum = get_table_num()
        query = string.format(query_map[join_name .. "_query"], sysbench.opt.table_name, tnum, get_record_status(), get_color())
        -- print("DEBUG JOIN QUERY B: " .. query .." Join Name: " .. join_name)
        con:query(query)
     end

Done!

Method 2

Just respect the rules as above but instead of using the existing map, you can create your own and then add it to the list query_map = mergeMultiple. As simple as that.

How to help

As said before, this is far from a perfect or exhaustive test, it is a start and the more feedback I get the more I will be able to improve it. 

I would really like to get PR or FR with specific tasks, the closer they are to real life cases the better.

In the meantime, I wish you all happy testing.

 

References

Joins sysbench code

MySQL 8.4: JOIN Clause – The definitive reference for INNER, LEFT, RIGHT, and CROSS joins.

Outer Join Optimization – Explains how the optimizer handles LEFT JOIN and RIGHT JOIN and how to write efficient predicates.

Nested-Loop Join Algorithm – For those interested in the "under the hood" execution of joins in MySQL.

Index Merge Optimization – Crucial for understanding how indexes are used (or not used) during complex joins.

 

 

 

 

 

 

mysql community performance Benchmark sysbench
6 comments on “joins... joins... everywhere”

More Articles …

  1. The 10 TB Scale Survival Guide for Percona Operator PXC on Kubernetes
  2. MySQL January 2026 Performance review
  3. How to Set Up the Development Environment for MySQL Shell Plugins for Python
  4. MySQL latest performance review
  5. How to migrate a production database to Percona Everest (MySQL) using Clone
  6. Sakila, Where Are You Going?
  7. Is MySQL Router 8.2 Any Better?
  8. Export and import of MySQL passwords using caching_sha2 
  9. Proof of Concept: Horizontal Write Scaling for MySQL with Kubernetes Operator
  10. Which is the best Proxy for Percona MySQL Operator?
  11. Help! I am out of disk space!
  12. MySQL Dual password how to manage them programmatically
  13. ProxySQL support for MySQL caching_sha2_password
  14. Zero impact on index creation with Aurora 3
  15. A face to face with semi-synchronous replication
  16. Online DDL with Group Replication In MySQL 8.0.27
  17. A look into Percona XtraDB Cluster Non Blocking Operation for Online Schema Upgrade
  18. What if … MySQL’s repeatable reads cause you to lose money?
  19. MySQL on Kubernetes demystified
  20. Compare Percona Distribution for MySQL Operator VS AWS Aurora and standard RDS
  21. Boosting Percona MySQL Operator efficiency
  22. MySQL Static and Dynamic privileges (Part1)
  23. MySQL Static and Dynamic privileges (Part2)
  24. 260 (Thousands) thanks
  25. Percona Live 2021 - my agenda picks
  26. Inconsistent voting in PXC
  27. Online DDL with Group Replication Percona Server 8.0.22 (and MySQL 8.0.23)
  28. What you can do with Auto-failover and Percona Server Distribution (8.0.x)
  29. Percona Distribution for MySQL: High Availability with Group Replication solution
  30. Who is drop-in replacement of 
  31. Full read consistency within Percona Operator for MySQL
  32. Percona Operator for MySQL (HAProxy or ProxySQL?)
  33. Support for Percona XtraDB Cluster in ProxySQL (Part Two)
  34. Support for Percona XtraDB Cluster in ProxySQL (Part One)
  35. Aurora multi-Primary first impression
  36. MySQL Asynchronous SOURCE auto failover
  37. Using SKIP LOCK in MySQL For Queue Processing
  38. Deadlocks are our Friends
  39. Achieving Consistent Read and High Availability with Percona XtraDB Cluster 8.0 (Part 2)
  40. Achieving Consistent Read and High Availability with Percona XtraDB Cluster 8.0 (Part 1)
  41. Sysbench and the Random Distribution effect
  42. #StopTRUMP
  43. Dirty reads in High Availability solution
  44. My take on: Percona Live Europe and ProxySQL Technology Day
  45. Another time, another place… about next conferences
  46. A small thing that can save a lot of mess, meet: SET PERSIST
  47. My first impression on Mariadb 10.4.x with Galera4
  48. Reasoning around the recent conferences in 2019
  49. ProxySQL Native Support for Percona XtraDB Cluster (PXC)
  50. MySQL High Availability On-Premises: A Geographically Distributed Scenario
Page 2 of 25
  • Start
  • Prev
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • Next
  • End

Related Articles

  • The Jerry Maguire effect combines with John Lennon “Imagine”…
  • The horizon line
  • La storia dei figli del mare
  • A dream on MySQL parallel replication
  • Binary log and Transaction cache in MySQL 5.1 & 5.5
  • How to recover for deleted binlogs
  • How to Reset root password in MySQL
  • How and why tmp_table_size and max_heap_table_size are bounded.
  • How to insert information on Access denied on the MySQL error log
  • How to set up the MySQL Replication

Path

  1. Home
  2. Technical Tips
  3. MySQL
  4. Geographic replication with MySQL and Galera

Latest conferences

We have 12905 guests and no members online

login

Remember Me
  • Forgot your username?
  • Forgot your password?
Bootstrap is a front-end framework of Twitter, Inc. Code licensed under MIT License. Font Awesome font licensed under SIL OFL 1.1.