NipGeihou's blog NipGeihou's blog
  • Java

    • 开发规范
    • 进阶笔记
    • 微服务
    • 快速开始
    • 设计模式
  • 其他

    • Golang
    • Python
    • Drat
  • Redis
  • MongoDB
  • 数据结构与算法
  • 计算机网络
  • 应用

    • Grafana
    • Prometheus
  • 容器与编排

    • KubeSphere
    • Kubernetes
    • Docker Compose
    • Docker
  • 组网

    • TailScale
    • WireGuard
  • 密码生成器
  • 英文单词生成器
🍳烹饪
🧑‍💻关于
  • 分类
  • 标签
  • 归档

NipGeihou

我见青山多妩媚,料青山见我应如是
  • Java

    • 开发规范
    • 进阶笔记
    • 微服务
    • 快速开始
    • 设计模式
  • 其他

    • Golang
    • Python
    • Drat
  • Redis
  • MongoDB
  • 数据结构与算法
  • 计算机网络
  • 应用

    • Grafana
    • Prometheus
  • 容器与编排

    • KubeSphere
    • Kubernetes
    • Docker Compose
    • Docker
  • 组网

    • TailScale
    • WireGuard
  • 密码生成器
  • 英文单词生成器
🍳烹饪
🧑‍💻关于
  • 分类
  • 标签
  • 归档
  • MySQL

  • Redis

  • MongoDB

  • 分享

    • 数据库的选择
      • 前言
      • 关系数据库
        • 建表
        • 插入
        • 查询
      • 时序数据库
        • 建表
        • 插入
        • 查询
      • 参考
  • 数据库
  • 分享
NipGeihou
2023-06-02
目录

数据库的选择

# 前言

玩家每参加一次游戏就可以获得 1 积分,现有需求需要统计游戏中过去 24 小时玩家积分排名,当前用户量约 200 万,未来会进一步增长。假设平均每人每天玩 3 次,那么每天约有 600 万的数据量,而需要对这 600 万的数据进行近乎实时的聚合统计。

挖坑待埋!!

# 关系数据库

单机 MySQL8 为例

# 建表

CREATE TABLE `point` (
	`id` INT(10) NOT NULL AUTO_INCREMENT,
	`point` INT(10) NOT NULL COMMENT '本次获得/扣减积分',
	`user_id` INT(10) NOT NULL COMMENT '用户id',
	`create_time` DATETIME NOT NULL COMMENT '创建时间',
	PRIMARY KEY (`id`) USING BTREE
)
COLLATE='utf8mb4_general_ci'
ENGINE=InnoDB
;

# 插入

随机生成 500 万条记录

Point point = new Point();
int userId = (int) (Math.random() * 1000000) + 1;
point.setUserId(userId);
Date date = new Date();
// 随机生成一个最近48小时内的时间
date.setTime(date.getTime() - (long) (Math.random() * 48 * 60 * 60 * 1000));
point.setCreateTime(date);
int pointValue = (int) (Math.random() * 5) + 1;
point.setPoint(pointValue);

# 查询

查询 SQL:

SELECT SUM(p.`point`) AS total_points,p.user_id
FROM `point` p
WHERE p.create_time > DATE_SUB(NOW(), INTERVAL 1 DAY)
GROUP BY p.user_id
ORDER BY total_points DESC
LIMIT 10;

未加索引时的耗时情况:

行数 / 万 耗时 / 秒
100 8
150 10
200 16
300 25
400 32
500 38
  • 在 create_time 字段添加索引,耗时没变化,explain:没走索引, Using where; Using temporary; Using filesort
  • 在 user_id 字段添加索引,耗时超过 2 分钟,explain:显示走了索引,但反而耗时变长
  • 删除索引恢复原来耗时时长

# 时序数据库

timescale/timescaledb:2.11.0-pg14 为例

# 建表

使用 ChatGPT 转换的

CREATE TABLE point (
    id int4 NOT NULL DEFAULT nextval('point_id_seq'::regclass),
    point INT NOT NULL,
    user_id INT NOT NULL,
    create_time TIMESTAMP NOT NULL
);

COMMENT ON TABLE point IS '积分表';
COMMENT ON COLUMN point.point IS '本次获得/扣减积分';
COMMENT ON COLUMN point.user_id IS '用户id';
COMMENT ON COLUMN point.create_time IS '创建时间';

转超表

SELECT create_hypertable('point','create_time');

笔记

原表中不能用唯一索引,或者需要将唯一索引包含 create_time 字段。否则会报错: ERROR: cannot create a unique index without the column "create_time" (used in partitioning)

# 插入

这里我使用的 Navicat 从 MySQL 导出 CSV,再导入。

# 查询

SELECT SUM(p.point) AS total_points, p.user_id
FROM point p
WHERE p.create_time > NOW() - INTERVAL '1 DAY'
GROUP BY p.user_id
ORDER BY total_points DESC
LIMIT 10;

执行耗时约 3.8 秒,相较于 MySQL 的 38 秒提升明显

# 参考

  • Timescale Documentation | Get started with Timescale (opens new window)
上次更新: 2023/06/02, 16:55:07
Python实践

← Python实践

最近更新
01
Docker Swarm
04-18
02
安全隧道 - gost
04-17
03
Solana最佳实践
04-16
更多文章>
Theme by Vdoing | Copyright © 2018-2025 NipGeihou | 友情链接
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式