有关于存储过程的一个笑话

     我真的是上来讲一个笑话的,这是个传统笑话,需要慢慢讲。

     我同事离职以后,统计平台的所有代码就被我接过来了。这个统计平台是用MySQL搭建的,5.1版本,服务器是DELL的,有16个CPU和32G内存,700G的data空间,说真的这个配置对于我这种喜欢IOE的人来说实在是看不下去。

     接过这个系统后我发现有一个过程需要跑三个小时,从前4点开始跑,到早上9点前也就出来了,于是也就没有什么。可是后来因为生产服务器压力很大,ETL的时间被推后了很多,导致我的过程只能7点开始跑,这样子,加上数据入库,这个系统的日报往往要11点甚至12点才能跑出来,领导问我为什么没有数据的时候我真的不知道该如何狡辩。于是我想到了把计算过程迁移到Oracle上。我也这么做了,效果很好,这个三小时过程Oracle只需要不到1分钟然后spool出来load data都比原来的过程快很多倍。于是我就安心的用起了Oracle。

     但是我今天工程师精神泛滥了,我想知道为什么同样是数据库,人家阿里能把性能调校的那么好,我们就要等那么久?

     我跟踪了一下,最慢的是这样的一个SQL:

    

select distinct b.name 
from table_a a 
inner join table_b b
 on a.id = b.id
group by b.name

     其中A表1亿余数据,B表2千万左右,数据量可以说已经很大了。a的ID有一个索引,explain了以后这个SQL也走了索引,两个表都走了。这就很奇怪了,于是继续看执行计划,extra那里有个temp table还有一个filesort。于是我开始想笑,这是谁啊,distinct了还要group by一下b.name?于是我检视了一下b的表结构,这个表上的name是有一个索引的。我于是懂了从前的程序员为什么要画蛇添足的加一个group by。这在Oracle程序员看来是愚蠢的行为里,其实蕴含了一个MySQL的小技巧。我接触MySQL不长时间,但是通过读各种书籍发现MySQL的索引很有趣,尤其是聚集索引,整个InnoDB表就是一个索引。
      扯远了,这个SQL里,就是因为这个group by让b表也走了索引,但是,当时的程序员应该是忘掉了去掉前面的distinct,于是导致了悲剧的发生。

      这个SQL完整版是这样子的:

     

insert into table_c(day_id, name, flag)
select '20131128', distinct b.name, 1
from table_a a 
inner join table_b b
 on a.id = b.id
group by '20131128', b.name;

      去掉了distinct以后这个SQL还是很慢,半天插入不了。table_c有很多索引,这是个典型的DW表,很大。于是我建了一个中间表,只有一个字段name,可是我发现插入的速度还是很慢,非常慢,于是我想起了几天前我看的《高性能MySQL》,里面169页还是179页讲过页分裂的概念,提及了一个小技巧,就是每个表都应该有一个自增的主键,这样子插入速度会有一定的提升,于是我把mid表改了,有两个字段:id,name,其中id是自增的主键。这样一来,插入mid表只需要5min左右,而把mid表用简单的select语句插入table_c只需要20s。是我想要的效率。

     我学习MySQL只有短短的几个月时间,而且没有时间从最基础的开始学,都是需要什么知识就赶紧去看《高性能MySQL》,这本书真不错,当做一本救急用的字典确实可以满足作为一个开发人员的需要。当然了,我的定位是开发型DBA,这本书里讲管理入门的还比较少,我还是要好好学习。欢迎大家指正。

你可能感兴趣的:(有关于存储过程的一个笑话)