暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

适用于Postgres和MySQL的实时SQL缓存引擎

原创 库海无涯 2024-09-05
156

##

适用于Postgres和MySQL的实时SQL缓存引擎

1、什么是ReadySet

ReadySet is a transparent database cache for Postgres & MySQL that gives you the performance and scalability of an in-memory key-value store without requiring that you rewrite your app or manually handle cache invalidation. ReadySet sits between your application and database and turns even the most complex SQL reads into lightning-fast lookups. Unlike other caching solutions, it keeps cached query results in sync with your database automatically by utilizing your database’s replication stream. It is wire-compatible with Postgres and MySQL and can be used along with your current ORM or database client.

2、Readyset Demo for PostgreSQL

1. Download and run the Readyset Docker compose file

curl -L -o compose.yml                                  \
  "https://readyset.io/quickstart/compose.postgres.yml" \
  && docker compose pull                                \
  && docker compose up -d

2. Import sample data

curl -L -s "https://readyset.io/quickstart/imdb-postgres.sql" \
  | psql 'postgresql://postgres:readyset@127.0.0.1:5433/testdb'

Data loading will be slow on Macs with Apple Silicon.

3. Connect and explore the dataset

Connect to Readyset.

psql 'postgresql://postgres:readyset@127.0.0.1:5433/testdb'

Enable query timing.

\timing

Run a sample query. Note that since we have not created a cache, this query is served directly by Postgres.

SELECT count(*) FROM title_ratings
JOIN title_basics ON title_ratings.tconst = title_basics.tconst
WHERE title_basics.startyear = 2000 AND title_ratings.averagerating > 5;

You’ll see similar results:

 count
-------
  2418
(1 row)

Time: 154.980 ms

4. Cache a query!

Query performance will be slow on Macs with Apple Silicon.

Using the CREATE CACHE FROM SQL extension, cache the query in Readyset like so:

CREATE CACHE FROM SELECT count(*) FROM title_ratings
JOIN title_basics ON title_ratings.tconst = title_basics.tconst
WHERE title_basics.startyear = 2000 AND title_ratings.averagerating > 5;

Now that Readyset is going to cache the query, run the same query to populate the cache:

SELECT count(*) FROM title_ratings
JOIN title_basics ON title_ratings.tconst = title_basics.tconst
WHERE title_basics.startyear = 2000 AND title_ratings.averagerating > 5;

Same results as earlier:

 count(*)
----------
     2418
(1 row)

Time: 154.980 ms

This most recent query ran against Postgres, but now the Readyset cache has been populated.
Run the query again and this time it’s served by Readyset:

 count(*)
----------
     2418
(1 row)

Time: 2.073 ms

5. View Cached Queries

Use the SHOW CACHES command to see which queries are currently being cached by Readyset:

      query id      |     cache name     |                       query text                       | fallback behavior | count
--------------------+--------------------+--------------------------------------------------------+-------------------+-------
 q_bccd97aea07c545f | q_bccd97aea07c545f | SELECT                                                +| fallback allowed  | 4
                    |                    |   count(*)                                            +|                   |
                    |                    | FROM                                                  +|                   |
                    |                    |   "title_ratings"                                     +|                   |
                    |                    |   JOIN "title_basics" ON (                            +|                   |
                    |                    |     "title_ratings"."tconst" = "title_basics"."tconst"+|                   |
                    |                    |   )                                                   +|                   |
                    |                    | WHERE                                                 +|                   |
                    |                    |   (                                                   +|                   |
                    |                    |     ("title_basics"."startyear" = $1)                 +|                   |
                    |                    |     AND ("title_ratings"."averagerating" > 5)         +|                   |
                    |                    |   )                                                    |                   |
(1 row)

6. Update the underlying data

You’ll notice that query you’ve run a few times returns the count of movies in '00 that had a rating greater than 5 (i.e. 2,418 movies). “Battlefield Earth” was a movie released in '00 that received poor ratings. For instance, run this query:

 SELECT title_basics.tconst, title_basics.primarytitle, title_ratings.averagerating, title_ratings.numvotes 
 FROM title_basics                                                
 INNER JOIN title_ratings on title_ratings.tconst = title_basics.tconst                                                                                                               
 WHERE title_basics.primarytitle = 'Battlefield Earth';

You’ll see it scored an average rating of 2.5:

  tconst   |   primarytitle    | averagerating | numvotes
-----------+-------------------+---------------+----------
 tt0185183 | Battlefield Earth |           2.5 |    80451
(1 row)

Time: 63.621 ms

It was, indeed, an awful movie. Nevertheless, historical revisionism is fun when you have full control of the data. You can grab the id for “Battlefield Earth” (tt0185183) and update its average rating accordingly:

UPDATE title_ratings
SET averagerating = 5.1
WHERE tconst = 'tt0185183';

7. The cache is auto-updated!

Rerun the previously cached query that returns the count of movies:

SELECT count(*) FROM title_ratings                                                                                                                                         
JOIN title_basics ON title_ratings.tconst = title_basics.tconst                                                                                                                      
WHERE title_basics.startyear = 2000 AND title_ratings.averagerating > 5;

And bingo! The count has been increased by one (i.e 2,419 vs 2,418).

 count(*)
----------
     2419
(1 row)

Time: 2.617 ms

8. Try more queries!

Explore the dataset and test Readyset’s performance with additional queries.

View proxied queries:

SHOW PROXIED QUERIES;

Remove a cache:

DROP CACHE <query id>;

3、Readyset Demo for MySQL

1. Download and run the Readyset Docker compose file

curl -L -o compose.yml                                  \
  "https://readyset.io/quickstart/compose.mysql.yml"    \
  && docker compose pull                                \
  && docker compose up -d

2. Import sample data

curl -L -s "https://readyset.io/quickstart/imdb-mysql.sql" \
  | mysql -h127.0.0.1 -uroot -P3307 testdb -preadyset

Data loading will be slow on Macs with Apple Silicon.

3. Connect and explore the dataset

Connect to Readyset.

mysql -h127.0.0.1 -uroot -P3307 testdb -preadyset

Run a sample query.

Note that since we have not created a cache, this query is served by MySQL.

Query:

SELECT count(*) FROM title_ratings
JOIN title_basics ON title_ratings.tconst = title_basics.tconst
WHERE title_basics.startyear = 2000 AND title_ratings.averagerating > 5;

Results:

+----------+
| count(*) |
+----------+
|     2418 |
+----------+
1 row in set (0.69 sec)

4. Cache a query!

Query performance will be slow on Macs with Apple Silicon.

Using the CREATE CACHE FROM SQL extension, cache the query in Readyset.

CREATE CACHE FROM SELECT count(*) FROM title_ratings
JOIN title_basics ON title_ratings.tconst = title_basics.tconst
WHERE title_basics.startyear = 2000 AND title_ratings.averagerating > 5;

Now that Readyset is going to cache the query, run the query to populate the cache.

Query:

SELECT count(*) FROM title_ratings
JOIN title_basics ON title_ratings.tconst = title_basics.tconst
WHERE title_basics.startyear = 2000 AND title_ratings.averagerating > 5;

Results:

+----------+
| count(*) |
+----------+
|     2418 |
+----------+
1 row in set (0.69 sec)

That query ran on the database, but now the Readyset cache has been populated. Run the query again, and this time it is served by Readyset.

Results:

+----------+
| count(*) |
+----------+
|     2418 |
+----------+
1 row in set (0.03 sec)

5. View Cached Queries

Use the SHOW CACHES command to see which queries are currently being cached by Readyset:

mysql> show caches;
+--------------------+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------+-------+
| query id           | cache name         | query text                                                                                                                                                                                           | fallback behavior | count |
+--------------------+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------+-------+
| q_cb4448c088a2c2f6 | q_cb4448c088a2c2f6 | SELECT count(*) FROM `title_ratings` JOIN `title_basics` ON (`title_ratings`.`tconst` = `title_basics`.`tconst`) WHERE ((`title_basics`.`startyear` = $1) AND (`title_ratings`.`averagerating` > 5)) | fallback allowed  | 2     |
+--------------------+--------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------------------+-------+
1 row in set (0.02 sec)

6. Update the underlying data

You’ll notice that query you’ve run a few times returns the count of movies in '00 that had a rating greater than 5 (i.e. 2,418 movies). “Battlefield Earth” was a movie released in '00 that received poor ratings. For instance, run this query:

 SELECT title_basics.tconst, title_basics.primarytitle, title_ratings.averagerating, title_ratings.numvotes 
 FROM title_basics                                                
 INNER JOIN title_ratings on title_ratings.tconst = title_basics.tconst                                                                                                               
 WHERE title_basics.primarytitle = 'Battlefield Earth';

You’ll see it scored an average rating of 2.5:

+-----------+-------------------+---------------+----------+
| tconst    | primarytitle      | averagerating | numvotes |
+-----------+-------------------+---------------+----------+
| tt0185183 | Battlefield Earth |           2.5 |    80451 |
+-----------+-------------------+---------------+----------+
1 row in set (0.13 sec)

It was, indeed, an awful movie. Nevertheless, historical revisionism is fun when you have full control of the data. You can grab the id for “Battlefield Earth” (tt0185183) and update its average rating accordingly:

UPDATE title_ratings
SET averagerating = 5.1
WHERE tconst = 'tt0185183';

7. The cache is auto-updated!

Rerun the previously cached query that returns the count of movies:

SELECT count(*) FROM title_ratings                                                                                                                                         
JOIN title_basics ON title_ratings.tconst = title_basics.tconst                                                                                                                      
WHERE title_basics.startyear = 2000 AND title_ratings.averagerating > 5;

And bingo! The count has been increased by one (i.e 2,419 vs 2,418).

+----------+
| count(*) |
+----------+
|     2419 |
+----------+
1 row in set (0.03 sec)

8. Try more queries!

Explore the dataset and test Readyset’s performance with additional queries.

View proxied queries:

SHOW PROXIED QUERIES;

Remove a cache:

DROP CACHE <query id>;

4、其他demo要求

4.1、Database Requirements

For Readyset to work properly, the following database settings are required:

  1. Logical replication must be turned on in your database
  2. Readyset must have superuser permissions

For directions on how to check and alter these configurations, please see our database reference documentation. The steps to configure these settings vary by database type and hosting provider.

4.2、Supported Database Versions
Database Type Versions Support Level
PostgreSQL 13.0+ Beta
MySQL 8.0 Alpha
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论