公司的系统采用的是 Google Cloud SQL 提供的 MySQL 数据库,由于历史原因,数据库成本极高,需要对它进行优化缩减成本。

相比 PostgresSQL,MySQL 主要缺少以下特性,导致优化难度极高:

1. 缺少部分索引。部分索引可以将一亿行数据中活跃的那部分数据(往往只有几百万行)隔离出来。

2. 缺少计算索引。MySQL 的索引不能是表达式。

3. 不支持并行。MySQL不能让一个查询分布到多个核,从而缩短查询执行时间。由于只能用一个核,运行时间较长的的SQL很容易造成锁超时,各个服务日志里充满了锁超时错误。

弃暗投明换PG或者上Lambda架构等做法都过于复杂,不考虑。

在优化过程中我发现,如 MySQL 能支持类似流视图,很多主要语句的执行问题可以迎刃而解。

什么是流视图?

基于 Postgresql 的 PipelineDB 支持 Continuous View,使数据库具备了类似流式计算的效果。

流式数据库PipelineDB(集成Kafka) - 简书

流计算风云再起 - PostgreSQL携PipelineDB力挺IoT(物联网), 大幅提升性能和开发效率-云栖社区-阿里云

采用速度层对新增数据执行计算后放入快速存储,而不是在查询时开始计算,这是 Lambda 之类大数据架构的精髓思想。流视图将这套架构包装为一个直观易懂的数据库新事物,和关系理论又不相违,是很巧妙的设计。显然,流视图在很多场景都可以取代 Spark 之类大数据架构,为用户提供更实时的统计查询服务。

羡慕是没用的,没有就自己搞,如何实现流视图?

流视图的原理可以想见:流视图本身是一个表,程序侦听视图相关的各个表的变化,将变化更新到相应的流视图的数据行。

侦听数据变化是实现流视图的必备基础。

在SQL中侦听变化的方式主要是触发器。给每个表建一个触发器很不明智,干出来也不漂亮。我想到一个很好的方案:BINLOG。找了一下,目前已有若干支持 binlog 转 MQ 的方案。我选择了 canal,备选 maxwell。在实施过程中发现,canal 往 MQ 推送的消息没有都是字符串且不支持枚举,而 maxwell 虽然消息很棒,还支持 js 做 filter,但是经常出错崩溃,CPU高,处理不了太大的 binlog,最终还是采用了 canal。相比来说 canal 一直在阿里实用,运行非常稳定,CPU 耗费低,从来不出错。

有了 BINLOG,后面就是搞发明创造了,做架构写代码,最终成果如下:

class HV_user_gender(HotView):
VIEW_SQL = '''
SELECT a.id, a.name, b.gender,b.age FROM a, b ON a.id = b.id WHERE b.age < 22
%s
''' def __init__(self, view_db: Engine, logger: logging.Logger, cache_db:Engine = None):
meta = MetaData()
mapping = [
TableMapping('a', meta,
ColumnMapping('id', cond_alias="a.id", view_alias="id", is_fixed=True, primary_key=True),
ColumnMapping('name', view_alias="name", is_fixed=False),
trace_insert=True), TableMapping('b', meta,
ColumnMapping('id', cond_alias="b.id", is_output=False, primary_key=True),
ColumnMapping('gender', view_alias="gender", is_fixed=True),
ColumnMapping('age', view_alias="age", is_fixed=False),
predicate=lambda row: int(row['age']) < 22
)
]
super().__init__(view_db, 'hot_user_gender', topics=['a', 'b'],
logger=logger,
primary_key="id",
view_sql=HV_user_gender.VIEW_SQL,
mapping=mapping,cache_db= cache_db) def init_view(self):
sql = '''
insert into hot_user_gender(id, name, gender, age)
''' + (self.view_sql % '')
r = self.view_db.execute(sql)
self.logger.info('init view insert %s items' % r.rowcount)

这里实现了一个基于 a b 两表的联合查询,b.age < 22 过滤条件的流视图。当 b.age 有变化时,如 b.age >= 22,视图行自动删除,如 b.age < 22,相应视图行更新。a 有增删时,视图行同步变化行。

该视图的代码不到100行,声明式代码风格。

目前对一个常用查询做了流视图改造,CPU 立即降低 15%!随处可见的 Read Lock timeout 之类异常也不见了。

流视图的改造成本很低,对于用 mybaits/ibatis 之类框架的程序来说,只要调整相关 SQL 代码,将原来的复杂查询挪到 python 中,替换成单表流视图的名称即可,原有的技术堆栈还能继续使用。什么难出的报表、加载耗时漫长的 dashboard,homepage,等等,都可以通过流视图改为实时秒开,不但用户体验上升,数据库压力也骤然下降,实乃 SQLer 的灵丹妙药,MySQL 这种弱爆了的数据库也有枯木逢春之感。

在 MySQL 创造类似 PipelineDB 的流视图(continuous view)的更多相关文章

  1. MySQL 系列(三)你不知道的 视图、触发器、存储过程、函数、事务、索引、语句

    第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 你不知道的数据库操作 第三篇:MySQL 系列(三)你不知道的 视图.触发器.存储过程.函数 ...

  2. 我的MYSQL学习心得(十一) 视图

    我的MYSQL学习心得(十一) 视图 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据 ...

  3. MySQL基础(二):视图、触发器、函数、事务、存储过程

    一.视图 视图是一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名称]即可获取结果集,并可以将其当作表来使用. 视图和上一篇学到的临时表搜索类似. ...

  4. python进阶10 MySQL补充 编码、别名、视图、数据库修改

    python进阶10 MySQL补充    编码.别名.视图.数据库修改 一.编码问题 #MySQL级别编码 #修改位置: /etc/mysql/mysql.conf.d/mysqld.cnf def ...

  5. Mybatis拦截器 mysql load data local 内存流处理

    Mybatis 拦截器不做解释了,用过的基本都知道,这里用load data local主要是应对大批量数据的处理,提高性能,也支持事务回滚,且不影响其他的DML操作,当然这个操作不要涉及到当前所lo ...

  6. MySQL实现类似Oracle的序列

    MySQL实现类似Oracle的序列 2013-10-22 10:33:35     我来说两句      作者:走过的足迹 收藏    我要投稿 MySQL实现类似Oracle的序列   Oracl ...

  7. 【转】MYSQL入门学习之十:视图的基本操作

    转载地址:http://www.2cto.com/database/201212/176775.html 一.视图的基本介绍  www.2cto.com           视图是虚拟的表.与包含数据 ...

  8. mysql统计类似SQL语句查询次数

    mysql统计类似SQL语句查询次数 vc-mysql-sniffer 工具抓取的sql分析. 1.先用shell脚本把所有enter符号替换为null,再根据语句前后的字符分隔语句 grep -Ev ...

  9. pipelinedb学习笔记 - 1. Continuous Views (连续视图)

    Continuous Views 一.Continuous Views 英文直译过来叫连续视图, 在pipelindb中是被定义为专门用来展示 Stream中数据用的.例如:Stream中有一些用户信 ...

  10. mysql基础教程(四)-----事务、视图、存储过程和函数、流程控制

    事务 概念 事务由单独单元的一个或多个SQL语句组成,在这 个单元中,每个MySQL语句是相互依赖的.而整个单独单 元作为一个不可分割的整体,如果单元中某条SQL语句一 旦执行失败或产生错误,整个单元 ...

随机推荐

  1. Vue 如何实现组件切换的时候,让组件缓存,不会被销毁

    使用场景:我们开发项目的时候,会遇到组件之间的切换,一般都是创建组件销毁组件来回切换 :但是现在需求是切换组件的时候,另一个组件不会销毁: 基于这个需求 ,我们使用 keep-live 组件包裹起来要 ...

  2. CEOI2022

    Day1 T1 Abracadabra 题意:给你一个 \(1 \sim n\) 的排列 \(p\),保证 \(n\) 为偶数,我们对它进行足够多次数的洗牌操作,定义一次洗牌为: 考虑取出 \(p_{ ...

  3. 基于 KubeSphere 部署 KubeBlocks 实现数据库自由

    作者:尹珉, KubeSphere Contributor & Ambassador,KubeSphere 社区用户委员会杭州站站长. KubeSphere 是什么? KubeSphere 是 ...

  4. KubeSphere 社区双周报 | 功能亮点抢“鲜”看 | 2022-09-30

    KubeSphere 从诞生的第一天起便秉持着开源.开放的理念,并且以社区的方式成长,如今 KubeSphere 已经成为全球最受欢迎的开源容器平台之一.这些都离不开社区小伙伴的共同努力,你们为 Ku ...

  5. C# 动态调用webservice代码

    /// <summary> /// 动态调用WebService /// </summary> /// <param name="url">UR ...

  6. SQL Server 安装图解

    此安装步骤适用于首次安装 一.SQL Server 安装 1.双击SQL Server 光盘映像文件,会出现如图所示界面 选择如下图所示的选项 2.输入产品密钥(这里演示密钥进行) 3.配置更新项,检 ...

  7. 教你删除Linux中这些因特殊字符命名无法删除的文件

    我们都知道,在Linux删除一个文件可以使用rm命令,但是有一些特殊名称的文件使用普通的rm方式却没法删除,本文介绍Linux中删除特殊名称文件的多种方式. Linux文件命名规则 在介绍之前,简单说 ...

  8. 配置NVIDIA Container Runtime和容器运行GPUStack教程

    GPUStack 是一个设计用于运行大模型的开源 GPU 集群管理器,提供私有部署的大模型服务,支持大语言模型.Embedding 文本嵌入模型.Reranker 重排序模型.Vision 多模态模型 ...

  9. 在哪里可以找到官方的mysql容器图像?

    如果您在容器上部署MySQL,那么首要任务之一就是找到正确的镜像. 有一定程度的混乱,尤其是当我们试图帮助部署有问题的人时. 例如,当人们说我使用的是官方的docker镜像- 这到底意味着什么?Doc ...

  10. Redis中的分布式锁(步步为营)

    分布式锁 概述 分布式锁指的是,所有服务中的所有线程都去获取同一把锁,但只有一个线程可以成功的获得锁,其他没有获得锁的线程必须全部等待,直到持有锁的线程释放锁. 分布式锁是可以跨越多个实例,多个进程的 ...