DEV Community

Cover image for Supercharge Your App: MariaDB In-Memory Tables as a Cache
Alejandro Duarte
Alejandro Duarte

Posted on • Originally published at programmingbrain.com

Supercharge Your App: MariaDB In-Memory Tables as a Cache

Redis is mainly used as an application cache or a quick-response database. But wait, you can always create a cache in a relational database as follows:

CREATE TABLE cache(
    ´key´ VARCHAR(64) PRIMARY KEY,
    value VARCHAR(255) NOT NULL,
    last_updated TIMESTAMP
        DEFAULT CURRENT_TIMESTAMP
        ON UPDATE CURRENT_TIMESTAMP
);
Enter fullscreen mode Exit fullscreen mode

Moreover, with MariaDB, you can pick one from the many available storage engines. For example, if you want to store the previous cache table in memory, simply use the MEMORY storage engine:

CREATE TABLE cache(
    ...
) ENGINE=MEMORY;
Enter fullscreen mode Exit fullscreen mode

When you configure the cache table to use the MEMORY storage engine, its data will reside entirely in RAM. This is interestingly similar to how Redis operates, keeping data in memory for low-latency access. This looks great and it definitely has its benefits. However, there are a few nuances that are worth exploring.

Example Use Case

Let’s say you have a web application that needs to track session IDs. Using a MariaDB MEMORY table sounds like a good idea here—there’s potential for reducing the load on your primary databases and improving response times for your users. Here's how you could implement such a cache using MariaDB’s MEMORY storage engine:

CREATE OR REPLACE TABLE users_cache (
    user_name VARCHAR(50) NOT NULL PRIMARY KEY REFERENCES users(id),
    session_id VARCHAR(50),
    last_updated DATETIME NOT NULL
        DEFAULT CURRENT_TIMESTAMP
        ON UPDATE CURRENT_TIMESTAMP
) ENGINE=MEMORY;
Enter fullscreen mode Exit fullscreen mode

Insertion into this table would typically occur whenever a user logs in. But generalizing a bit more, insertion in a cache could happen every time you read data stored on disk-based tables. We’ll use the later approach and assume that storing session IDs permanently is a business requirement just so that we can make more experiments. In any case, you can set up a background job to refresh this cache periodically or invalidate it when the underlying data changes.

Cache Invalidation and Management

There are several ways to handle cache invalidation with MariaDB. For example, you can set a limited row-based lifespan (through a column for expiration time) and use event schedulers to clear or update cached data at fixed intervals. Here’s an example:

CREATE OR REPLACE EVENT ev_remove_stale_user_cache_entries
    ON SCHEDULE EVERY 20 MINUTE DO
        DELETE FROM users_cache
        WHERE NOW() > last_updated + INTERVAL 2 HOUR;
Enter fullscreen mode Exit fullscreen mode

For testing you can use different intervals. For example EVERY 1 SECOND and INTERVAL 20 SECOND. Also, remember to enable MariaDB’s event scheduler by setting the event_scheduler configuration property or, for testing, by running:

SET GLOBAL event_scheduler = ON;
Enter fullscreen mode Exit fullscreen mode

If you want to try this out, you can find a complete example on GitHub. Or watch the short video demoing the example in action.

Pros and cons

Although using the MEMORY storage engine can speed up data retrieval times, as always, this depends on the exact use case—you should test this configuration with your applications before making decisions. In particular, it’s important to be aware that MEMORY performs table-wide locks. This means that it might not be well-suited when you need to update the cache more frequently than you read it. Or in other words, using the MEMORY storage engine is a good option for data that needs to be accessed frequently and updated infrequently.

A key advantage of using the MEMORY engine is when your app needs to mix cache data with data in tables of a relational database, for example, during a single HTTP request. Imagine an app that processes user information updates. Each update might involve writing to a cache and simultaneously updating a relational record. This would require two different accesses to two different databases. With MariaDB, you can handle this in a single database using SQL. This eliminates the overhead and complexity of managing separate data stores and coordinating between them. Here’s a simplified example of how such an operation could look:

SET @data = "other data";
UPDATE users SET data = @data WHERE id = 123;
REPLACE INTO users_cache (user_id, data) VALUES (123, @data);
Enter fullscreen mode Exit fullscreen mode

In this example, the user's data columns in both the users and the user_cache tables are updated in a single call to the database. Keep in mind that the MEMORY storage engine is not transactional, which is less important when you compare it with a cache that lives in a completely different database technology than your operational database anyway.

An additional and obvious but important advantage of using the MEMORY engine is that you can remove persistence-polyglot logic from your app. If your team is already familiar with SQL, MariaDB provides a seamless experience without the need to learn new syntax or juggle another technology stack.

How Does It Stack Up Against Redis?

While Redis is a powerful tool for handling simple data structures like strings, hashes, lists, sets, and sorted sets directly in-memory, MariaDB's MEMORY engine handles complex queries more naturally because it supports the full power of SQL and relational database systems. This means you can perform joins, subqueries, and even complex transactions, which are not as straightforward in Redis.

Now, there’s also the question of scalability. Especially horizontal scalability. This involves adding more nodes to a system to distribute load and increase capacity without interrupting service. Both Redis and MariaDB offer robust solutions, but their mechanisms are different.

Redis achieves horizontal scalability primarily through sharding, where data is partitioned across multiple Redis instances. This can be configured manually or managed via Redis Cluster, which handles sharding and provides high availability through failover and replication processes. Redis Cluster supports up to 1000 nodes, which allows it to scale massively. This model is particularly effective for applications requiring ultra-fast operations and high throughput on simple data structures.

MariaDB offers a somewhat similar approach to scalability. And you probably guessed it—this is achieved through a storage engine. The Spider engine partitions table data across multiple MariaDB nodes, treating them as one logical entity. This enables querying and updating data across various physical servers seamlessly as if they were on a single local server. The Spider engine supports SQL and transactional data operations so you can run complex queries when you need. It’s useful for large database environments where data distribution is essential for performance and management to meet the demands of large-scale applications.

Durability and Persistence

One difference to consider is that the MEMORY storage engine in MariaDB does not offer data persistence after server restarts. Data stored in MEMORY tables is volatile; it's cleared when the database restarts, much like Redis in its default configuration. If persistence is crucial, you might consider using MariaDB's Aria or InnoDB engines for caching. In fact, InnoDB has excellent performance, thanks to its cache mechanism, which reduces the load on primary nodes.

Final Thoughts

Switching from Redis to MariaDB for caching might not suit every project, but it's a viable option for those looking to streamline their technology stack or leverage their existing SQL expertise. It provides an easy way to implement caching solutions with tools you already know and reduces the overhead of managing additional systems. Plus, for those looking for a middle ground, MariaDB can also serve as a complementary caching layer alongside Redis, taking advantage of both systems' strengths. Moreover, you can leverage Redis as a cache for MariaDB MaxScale.

Try MariaDB and set up your own in-memory cache with the MEMORY storage engine. Experience how it fits with your existing SQL knowledge. I have created a simple plain-text file with detailed instructions and code that you can run to see a cache in action using only SQL! So all you need is to connect to your MariaDB server (spin one up quickly using Docker if you don’t have one running already) and run the commands in any SQL client compatible with MariaDB (most of them are). Here you can see the demo in action:

Supercharge Your App: MariaDB In-Memory Tables for Caching

If you have questions or want to share your experience, don’t hesitate to join the MariaDB Community Slack and let us know!

Top comments (0)