写点什么

我是如何用 2 个 Unix 命令给 SQL 提速的

  • 2018-08-12
  • 本文字数:2726 字

    阅读完需:约 9 分钟

我试图在 MariaDB(MySQL)上运行一个简单的连接查询,但性能简直糟糕透了。下面将介绍我是如何通过两个简单的 Unix 命令,将查询时间从 380 小时降到 12 小时以下的。

下面就是这个查询,它是 GHTorrent 分析的一部分,我使用了关系在线分析处理框架 simple-rolap 来实现这个分析。

复制代码
select distinct
project_commits.project_id,
date_format(created_at, '%x%v1') as week_commit
from project_commits
left join commits
on project_commits.commit_id = commits.id;

两个连接字段都有索引。不过,MariaDB 是通过对 project_commits 进行全表扫描和对 commits 进行索引查找来实现连接的。这可以从 EXPLAIN 的输出看出来。



这两个表中的记录比较多:project_commits 有 50 亿行记录,commits 有 8.47 亿行记录。服务器的内存比较小,只有 16GB。所以很可能是因为内存放不下那么大的索引,需要读取磁盘,因此严重影响到了性能。从 pmonitor 对临时表的分析结果来看,这个查询已经运行半天了,还需要 373 个小时才能运行完。

复制代码
/home/mysql/ghtorrent/project_commits#P#p0.MYD 6.68% ETA 373:38:11

在我看来,这个太过分了,因为排序合并连接(sort-merge join)所需的 I/O 时间应该要比预计的执行时间要低一个数量级。我在 dba.stackexchange.com 上寻求帮助,有人给出了一些建议让我尝试,但我没有信心它们能够解决我的问题。我尝试了第一个建议,结果并不乐观。尝试每个建议都需要至少半天的时间,后来,我决定采用一种我认为可以有效解决这个问题的办法。

我将这两个表导出到文件中,使用 Unix 的 join 命令将它们连接在一起,将结果传给 uniq,把重复的行移除掉,然后将结果导回到数据库。导入过程(包括重建索引)从 20:41 开始,到第二天的 9:53 结束。以下是具体操作步骤。

1. 将数据库表导出为文本文件

我先导出连接两个表需要用到的字段,并按照连接字段进行排序。为了确保排序顺序与 Unix 工具的排序顺序兼容,我将字段转换为字符类型。

我将以下 SQL 查询的输出保存到文件 commits_week.txt 中。

复制代码
select cast(id as char) as cid,
date_format(created_at, '%x%v1') as week_commit
from commits
order by cid;

然后将以下 SQL 查询的输出保存到 project_commits.txt 文件中:

复制代码
select cast(commit_id as char) as cid, project_id
from project_commits
order by cid;

这样就生成了以下两个文件。

复制代码
-rw-r--r-- 1 dds dds 15G Aug 4 21:09 commits_week.txt
-rw-r--r-- 1 dds dds 93G Aug 5 00:36 project_commits.txt

为了避免内存不足,我使用 --quick 选项来运行 mysql 客户端,否则客户端会在输出结果之前尝试收集所有的记录。

2. 使用 Unix 命令行工具处理文件

接下来,我使用 Unix 的 join 命令来连接这两个文本文件。这个命令线性扫描两个文件,并将第一个字段相同的记录组合在一起。由于文件中的记录已经排好序,因此整个过程完成得很快,几乎就是 I/O 的速度。我还将连接的结果传给 uniq,用以消除重复记录,这就解决了原始查询中的 distinct 问题。同样,在已经排好序的输出结果上,可以通过简单的线性扫描完成去重。

这是我运行的 Unix 命令。

复制代码
join commits_week.txt project_commits.txt | uniq >joined_commits.txt

经过一个小时的处理,我得到了想要的结果。

复制代码
-rw-r--r-- 1 dds dds 133G Aug 5 01:40 joined_commits.txt

3. 将文本文件导回数据库

最后,我将文本文件导回数据库。

复制代码
create table half_life.week_commits_all (
project_id INT(11) not null,
week_commit CHAR(7)) ENGINE=MyISAM;
load data local infile 'joined_commits.txt'
into table half_life.week_commits_all
fields terminated by ' ';

结语

理想情况下,MariaDB 应该支持排序合并连接,并且在预测到备用策略的运行时间过长时,优化器应该使用排序合并连接。但在此之前,使用 70 年代设计的 Unix 命令就可以解决这个问题。

查看英文原文: https://www.spinellis.gr/blog/20180805/

2018-08-12 19:002154
用户头像

发布了 731 篇内容, 共 483.2 次阅读, 收获喜欢 2008 次。

关注

评论 1 条评论

发布
暂无评论
发现更多内容

Vue进阶(幺伍捌):vue组包 CssSyntaxError unclosed bracket 错误解决方法

No Silver Bullet

Vue 11月日更

Python代码阅读(第51篇):判断给定的数是否在给定的范围内

Felix

Python 编程 Code Programing 阅读代码

一招教你快速打造企业级数据可视化大屏

云智慧AIOps社区

开源 大前端 数据可视化 大屏可视化 大屏

【等保小知识】等保、分保以及关保分别是什么意思?

行云管家

网络安全 等保 等级保护 分保

lims实验室管理系统是什么?实验室信息管理系统介绍!

低代码小观

企业管理 管理系统 LIMS实验室信息管理系统 LIMS系统 信息管理系统

工程师什么时机最合适选择跳槽?

程序员泥瓦匠

面试 加薪 跳槽 升职

2021DevOps国际峰会·北京站|龙智展位盛况回顾

龙智—DevSecOps解决方案

DevOps Atlassian

Apache ShenYu源码阅读系列-基于Http长轮询的数据同步

子夜2104

网关 shenyu

一分钟带您了解,堡垒机主要功能有哪些?

行云管家

网络安全 服务器 堡垒机 等级保护

苏杰:爆款产品是把基本动作做到位的结果

博文视点Broadview

生成式AI,引领AI从“换脸”到“造脸”

海比研究院

滴滴开源DRouter:一款高效的Android路由框架,androidui开发工具

android 程序员 移动开发

漫谈MVVM(1)ViewModel_DataBinding核心原理,kotlin开发安卓游戏

android 程序员 移动开发

【LeetCode】求众数 IIJava题解

Albert

算法 LeetCode 11月日更

这一次,解决Flutter Dialog的各种痛点!

小呆呆666

flutter ios android dart dialog

Gartner发布2021企业低代码魔力象限,Mendix连续三年第一!

J2PaaS低代码平台

低代码 数字化 低代码开发平台

Mac 系统如何利用软链接在根目录创建文件夹?

程序员泥瓦匠

Mac 文件写入

dubbo 配置 loadbalance 不生效?撸一把源码

捉虫大师

dubbo

Eureka 源码之启动过程

悟空聊架构

Eureka 源码剖析 悟空聊架构

kubernetes系列随笔01:云原生发展

Geek_cd6rkj

Kubernetes 云原生 弹性

第四模块作业-设计千万级学生管理系统的考试试卷存储方案

彦欲

架构训练营

Redis 核心篇:图解 Redis 为什么这么快

码哥字节

redis 后端 Java 分布式 11月日更

滴滴国际化项目 Android 端演进,一个小例子彻底搞懂Android的MVP模式到底是什么

android 程序员 移动开发

【Flutter 专题】20 图解 ListView 下拉刷新与上拉加载 (三)【RefreshIndicator】

阿策小和尚

Flutter 小菜 0 基础学习 Flutter Android 小菜鸟 11月日更

手把手教你从零开始搭建个人博客,20分钟上手

老表

Hexo 个人博客 服务器 教程分享 11月日更

《黑客之道》- kali LInux之WireShark抓包及常用协议分析

学神来啦

网络安全 Wireshark 渗透 kali

「The Monthly Echo」十月社区成长回顾

SphereEx

数据库 开源 ShardingSphere 技术沙龙 SphereEx

滴滴DoKit Android核心原理揭秘之函数耗时,app架构图怎么做

android 程序员 移动开发

使用 Spring Boot 和 @SpringBootTest 进行测试

码界行者

Spring Boot 测试 test

告警风暴来袭,智能运维应如何化解?

云智慧AIOps社区

AIOPS 告警 技术学习 智能运维 时序数据

图解Java线程状态转换

程序猿阿星

Java并发 线程 线程状态

我是如何用2个Unix命令给SQL提速的_语言 & 开发_spinellis_InfoQ精选文章