存档

‘Linux专区’ 分类的存档

用Gprof优化or测试你的程序

2011年4月19日 小卢 46 条评论

       昨天去席老师哪里论文格式审查,回来再次修改论文。这一段时间,忙的简直要抽风了,改论文,看论文,再改论文…总算差不多了。

       最近写论文的时候,第五章要写到一个测试,其中包括性能测试。本意是想测出系统中每个模块的性能,也就是每个模块运行次数以及运行时间。经过一番的百度和谷歌,最后决定使用Linux平台的Gprof。Gprof是一个GNU Profiler工具,其中GProf可以打印出每个函数的运行次数以及运行消耗时间,并且可以打印出函数的调用关系,配合KProf还可以显示函数的调用关系树。因此本测试使用Gprof,可以查看进程处理时间耗费情况。

       使用Gprof之前,我们有必要了解一下他的工作原理:通过在编译和链接程序的时候(使用-pg编译和链接选项),gcc在应用程序的每个函数中都加入了一个名为mcount (or”_mcount”,or “__mcount”, 依赖于编译器或操作系统)的函数,也就是说你的应用程序里的每一个函数都会调用mcount,而mcount 会在内存中保存一张函数调用图,并通过函数调用堆栈的形式查找子函数和父函数的地址。这张调用图也保存了所有与函数相关的调用时间,调用次数等等的所有信息。

       Gprof的用法:gprof [ -b ] [ -e Name ] [ -E Name ] [ -f Name ] [ -F Name ] [ -L PathName ] [ -s ] [ -z] [ a.out [ gmon.out ... ] ]

       -b 不再输出统计图表中每个字段的详细描述。

       -p 只输出函数的调用图(Call graph的那部分信息)。

       -q 只输出函数的时间消耗列表。

       -e Name 不再输出函数Name 及其子函数的调用图(除非它们有未被限制的其它父函数)。可以给定多个 -e 标志。一个 -e 标志只能指定一个函数。

       -E Name 不再输出函数Name 及其子函数的调用图,此标志类似于 -e 标志,但它在总时间和百分比时间的计算中排除了由函数Name 及其子函数所用的时间。

       -f Name 输出函数Name 及其子函数的调用图。可以指定多个 -f 标志。一个 -f 标志只能指定一个函数。

       -F Name 输出函数Name 及其子函数的调用图,它类似于 -f 标志,但它在总时间和百分比时间计算中仅使用所打印的例程的时间。可以指定多个 -F 标志。一个 -F 标志只能指定一个函数。-F 标志覆盖 -E 标志。

       -z 显示使用次数为零的函数(按照调用计数和累积时间计算)。

使用例子:

       假如我写了一个程序count_data.cpp,如果要使用gprof的话,在编译程序的时候需要加上-pg,如下:

       g++ -gp -o count_data count_data.cpp

       编译没有错误的话,直接运行 count_data程序

       ./ count_data

运行过程序以后,会在程序当前文件夹下生成一个gmon.out文件,这个文件便是程序运行记录文件。下一步我们就可以使用gprof来读取分析该文件了。

       gprof –q test gmon.out

    如果你想多次运行程序并且记录函数运行时间,便可以用shell来实现。下面是我写的一个shell脚本。测试本程序运行。本程序被调用四次,每次传入不同参数。

#!/bin/sh
i=1
while [ $i -le 23 ]
do
echo $i
time ./count_data $i > null
cp gmon.out ${i}gmon.out
gprof -b count_data ${i}gmon.out > ${i}.txt
let i+=7
done 

通过上面shell的运行,程序会产生一下几个文件:

1.txt 2.txt 3.txt 4.txt

       我们可以统计该程序运行函数的时间来分析每个函数的性能。该功能可以对程序运行效率进行优化,也可以在写论文是完成测试。呵呵,下面是我的测试结果以及对测试结果的分析,直接在论文里复制出来了,懒得改了,呵呵

       本次测试过程如下,首先将数据库中数据清空,然后程序循环读取七天的离线数据,模拟在线统计一小时数据,进行处理。处理过程中记录下该数据记录条数,以及更新数据条数。对Gprof产生的gmon.out文件进行分析。依次运行和分析第二批数据、第三批和第四批数据。

       表1主要函数运行时间

函数名(耗时ms) 第一批 第二批 第三批 第四批
get_userid() 86733 116327 110690 120245
count_net() 54571 77240 70421 72147
update_max_area() 小于10 小于10 小于10 小于10
Insert_hourflow() 小于10 小于10 小于10 小于10
update_max_sc() 小于10 小于10 小于10 小于10
update_ip_num() 小于10 小于10 小于10 小于10
insert_top_ten() 小于10 小于10 小于10 小于10
heap_adjust() 小于10 小于10 小于10 小于10
其他代码 39395 39086 54410 48099
总耗时 180699 232653 235521 240491

 

       表2主要函数运行次数

函数名(次数) 第一批 第二批 第三批 第四批
get_userid() 13498152 15346753 14668286 14059765
count_net() 1885952 2377368 2317642 2342265
update_max_area() 1 1 1 1
Insert_hourflow() 1 1 1 1
update_max_sc() 1 1 1 1
update_ip_num() 1 1 1 1
insert_top_ten() 1 1 1 1
heap_adjust() 247 321 276 229
数据条数 13498152 15346753 14668286 14059765

       由表1和表2可以看出,第一次数据处理中共统计出13498152条记录,其中有1885952用户匹配成功,其他数据不在监控范围内,因此被get_userid()函数过滤掉,count_net()函数被调用了1885952次,耗时54571ms,数据库插入函数仅仅被调用了一次,耗时非常小,可以被忽略掉。表1第一批数据总体耗时为180699ms,用户过滤模块耗时较多,达到86733ms,接近50%。因为每条记录均要过滤,所以耗时较多,其他代码耗时39395ms。其他代码耗时主要表现在程序环境初始化、读取离线数据文件、调用存储过程等。在表2可以分析得知,四次数据处理数据文件整体记录数大致在一千五百万左右。用户匹配成功以后的数据调用count_net()函数处理的记录数大概在二百万左右。分析表1可知,程序主要耗时在get_userid()和count_net(),这两个函数分别为用户过滤模块和数据处理模块。另外由表1可得第一批数据处理耗时比第二、三、四批数据少,因为第一批数据条数较少。还可以分析到,处理响应时间在第一批到第四批的整个过程略微有些增长。此现象是正常的,因为数据库在第一批处理过程中是空的,随着记录的增多数据库表中记录会增长。

       根据上面的分析我们可以看出,系统满足对记录数据处理的响应速度。处理千万级数据,耗时仅仅为三到五分钟,因此该数据处理过程满足需求。

分类: Linux专区, 编程 标签:

AWK学习笔记—从C语言的角度考虑AWK

2010年11月27日 小卢 4 条评论

从C语言的角度考虑AWK—AWK学习笔记

最近了解脚本,学习到了awk,感觉awk还是神似C语言,作为C语言常用者,如果使用到awk来处理数据,上手应该是比较快速了。

       首先说下,为什么使用awk。第一:awk写出来的数据处理,可移植性强。第二;awk比较简单,用C语言来处理脚本,你可能要写代码,断点调试,折腾一天,或者是一个下午,但是用awk,你一两个小时就可以搞定一个脚本。也许你会说,awk写出来的脚本绝对要比C/C++处理数据慢,是滴,这一点我们要承认,但是据网上大牛们的测试,发现,其实awk处理数据也不是我们想象那么慢,如果你真的感觉速度慢的话,可以先用awk实现了思想,回头来写C的代码,也是很好的一个提高效率的方法。

       为什么说要在C语言的角度来考虑awk脚本呢?因为身为脚本语言的awk,和C语言有很多相似之处。

      1. awk中的变量
        我们知道C语言中变量属于强定义语言。但是awk身为脚本,就有了脚本的特性:若定义语言,一个遍历,不用定义,拿来就可以用,而且初始值为空(或者是0)。那么一个变量,你可以认为它是float、string 等等。这里有一点,若定义语言其实也分字符和数字的,例如“123”,123是截然不同的两个变量,但是他们转换又是非常简单s = “123” # 此处是字符串。n = 0 + s ,这样n就成了数字123 。

     2. awk中的数组
           说道awk中的数组,可能有些特殊了,awk允许你用字符串作为下标。使用C语言的同学看到这一点也许就会笑了,这个特性岂不是牺牲效率换来的?其实如果你仔细去看gawk的源代码就会发现,gawk中数组的实现还是蛮复杂的,array_init()就可以看到,其中array下标的操作以及实现使用了hash算法。还是满巧妙的。
        Awk支持使用for (iggy in foo),这个令awk的实现负责了不少。

    3. awk中的数值运算符
        awk支持C语言中的大部分数值运算符:++ — ^ ! 等等

    4. awk中的语句
     回车识别语句结束,C语言中是分号了,如果你想把多条语句写到一行上就用分号隔开。
awk同样支持分支语句,用法和C语言中一样。当然啦还有循环,while ,do while for 等 这些都和C中用法一样。

   5. 其他
    awk中同样需要交互性操作:输入和输出。
其中输入可以接受用户键盘输入和重定向输入。Getline
输出的话就比较多了,可以使用print 和 printf函数,其中printf的使用方法和C语言中一样。

分类: Linux专区 标签:

TCP状态以及相关问题分析 -由面试问题想到的

2010年11月6日 小卢 8 条评论

以前做项目的时候,没有深入的考虑过这些问题,只是和同学在讨论问题的时候稍微摄入过TCP状态的一些问题。最近找工作国内两个比较大的互联网公司都问了相关问题。突然间感觉到TCP在网络编程中还是很重要,包括他的原理以及具体函数的意义。所以今天就整理了下TCP三次握手,以及相关的问题。

1.TCP状态转换中的小问题: 

连接建立:

我们从上面的图就可以看到,黑色加粗线是客户端的正常变迁过程。其中就是主动打开发动SYN以后,接受SYN,ACK后进入连接状态。

还有看黑色虚线是服务器的正常变迁过程。其中listen被动打开,指定一个接受队列,等收到SYN后发送ACK,SYN,然后收到ACK以后进入连接状态,通过accept函数返回客户端信息以及连接句柄。

断开连接:

由主动发起方发起FIN(注:通常但不是总是客户端发起断开连接),被动关闭方收到FIN发ACK,主动发起方收到ACK进入fin_wait2状态,如果收到FIN以后再次发送ACK就进入了TIME_WAIT状态,TIME_WAIT状态比较特殊,要等一个2MSL时间,就是一个二倍的网络延迟。

被动发起方发送FIN以后进入LAST_ACK,收到ACK后退出连接。

这里有个问题。主动发起方为什么要有个2MSL呢?如果没有会怎么样呢?我们可以看到,2MSL这个时候,连接基本上算关闭了,因此可以停止通信了,LAST_ACK状态的如果收不到ACK怎么办?一直等待?他应该是重发FIN,这个时候如果TIME_WAIT不存在,被动发起方就会收到一个RST,影响稳定性。如果2MSL存在,就会有一个问题。如果有人利用这个问题造成服务器出现大量的TIME_WAIT状态,因此这个是一个稳定性和效率的均衡。

2.另外再次讨论一下listen以后服务器协议栈做了那些工作:

Listen(int sockfd,int backlog)//0-成功,  -1失败 

由上面的示意图,可以看出,当Listen以后就可以接受对方的连接。当时面试的时候就遇到了这个问题,hr问我,Listen之后能接受客户端连接吗?如果能的话,是什么情况?连接以后客户端发送一系列信息会出现什么情况?呵呵,从上面的原理,我们应该看到比较清楚了,可以接受连接,并且理论上可以接受buffer大小的数据。

3.相关问题讨论,这些问题是我在面试以及在学习中,自己思考或者和同学讨论的结果。

A.当连接成功建立后,客户端拔去网线,客户端电脑重启后插入网线,启动客户端进程,会出现什么情况?

分析:首先如果TCP打开了keeplive选项,那么客户端关机时间久了以后,服务器就能感知到,如果keeplive关闭,或者客户端快速重启,那么这个时候,服务器没有发现异常。客户端重启过后是一个全新状态,由TCP状态转换图可知,客户端会发起SYN,而服务器收到客户端发来的SYN的话,发现在ESTABLISHED状态收到SYN是异常的,于是,返回RST,自己也复位改连接。客户端收到RST后,复位,重新连接。

B. 当连接成功建立后,如果send函数发送数据立即返回后,拔掉客户端网线,请问数据会在那些地方存留?

分析:send是glib函数通过系统调用传入内核协议栈的buffer中,然后队列等待发送。如果当前没有数据等待的话,该数据部分可能已经发送到网络上,但是也有可能正在buffer队列中等待发送。

C.当连接成功建立后,如果send函数发送数据立即返回后,且保证数据已经正常发送到网络上,这个时候拔掉服务器网线,会出现什么情况?

分析:首先服务器如果没有发送数据,只是等待接受的话,那么服务器可能等到了数据,也有可能永远等不到数据。如果网络状态非常好,在拔去网线之前已经收到了数据,或者网络不太好,数据还没有到达服务器。那么数据还是会正常传输,至少第一个数据包会正常传输,传到和服务器直接相连的交换机这里。交换机发现ip不通,通过arp广播寻求服务器mac,失败后,返回ICMP数据包:目的地址不可达。客户端收到数据包后感知服务器不可达。

D.在处于TIME_WAIT状态下,2MSL前,对方再次简历连接,请问连接可以简历成功吗?

分析:这个问题我就不打字了,网上分析的不错:书中给的图里面,有一个TIME_WAIT等待状态,这个状态又叫做2MSL状态,说的是在TIME_WAIT2发送了最后一个ACK数据报以后,要进入 TIME_WAIT状态,这个状态是防止最后一次握手的数据报没有传送到对方那里而准备的(注意这不是四次握手,这是第四次握手的保险状态)。这个状态在很大程度上保证了双方都可以正常结束,但是,问题也来了。由于插口的2MSL状态(插口是IP和端口对的意思,socket),使得应用程序在2MSL时间内是无法再次使用同一个插口的,对于客户程序还好一些,但是对于服务程序,例如httpd,它总是要使用同一个端口来进行服务,而在2MSL时间内,启动httpd就会出现错误(插口被使用)。为了避免这个错误,服务器给出了一个平静时间的概念,这是说在2MSL时间内,虽然可以重新启动服务器,但是这个服务器还是要平静的等待2MSL时间的过去才能进行下一次连接。

分类: Linux专区, 编程 标签:

你精通C语言吗?–由一次面试的亲身体会想到的…

2010年10月13日 小卢 27 条评论

 

读研这两年,平时项目都在用C语言在Linux下做,两年下来,也写了不少的代码,再加上我平时的不懈努力,多看书,也算是C语言的基础知识比较扎实了,因此在自己的简历上,就写上了“精通C语言编程”;这个在面试华为、中兴以及华赛的时候,都还好,问的问题都没有被卡壳,但是就在前几天,我去成都面试某互联网公司的时候,就结结实实的被打击了一下:当时面试管GG 看到我简历上写的“精通C语言编程”,就说:你精通C语言编程啊?我当时就一个汗啊!GG又说:那好吧!我给你说个最简单的吧:

struct empty{ }a ; //sizeof(a)

我只记得 在C++里面 空class 是 1;但是 在C语言的标准下,就不太好说了4? 1? 0? ,我一时之间想不到为什么了,这样的东西和编译器有关系?

当时大脑飞速运转,思考很多知识,总结推理…

回答:C++的标准下是1,C语言里面不确定,但是我推测是0或者4,原因:….

面试官GG 笑而不语。

我晓得自己回答的,他肯定不太满意。

然后GG接着问:问什么在C++中是1呢?

汗!这次是真的回答不上来了,由此想到自己还是真的不能堪称“精通C”啊!

回来以后,在VC下试了一下 结果是1,GCC下试了一下是0;

看来这个问题和编译器有关系啊!

再想一下,不免可以有一个比较清楚的认识了:每个结构体,编译器在处理的时候,都要对他进行识别,空的结构体就不能用结构体内部来识别他,就要编译器帮忙,这样的话,VC就产生了一个字节的空间来存储结构体的标识。GCC在处理的过程中节省了空间,但是他是怎么识别的呢?呵呵,回头想一下,其实两个空的结构体是没有用的,识别与否关系不太大!

由这个题目,我还想起来一个知识点:

#define print( n ) printf( “data”#n” = %d\n “, data##n )
int main()
{
      int data5=100;
      print(5);
      return 0;
}

上面这个代码是多少呢?有没有思考过呢?平时做项目的时候有没有用到过呢?

呵呵,如果我告诉你 结果是 :data5=100;
你会不会有些惊讶?

为什么是这样的呢?我们要从#号的功能谈起了
# 本身为指令 没有其他意义,也没有其他效果
# 号必须是该行除了任何空白字符外的第一个字符。预处理指令就是以#号开头的代码行。
# 后是指令关键字,在关键字和#号之间允许存在任意个数的空白字符。
整行语句构成了一条预处理指令,该指令将在编译器进行编译之前对源代码做某些转换。

下面举例说明下:
形式为: #define 标识符 字符串.
其中的“#”表示这是一条预处理命令。凡是以“#”开头的均为预处理命令。 #x中的#是字符串化运算符,作为是把参数x字符串化,即用双引号包围,例如,在这个程序中:

print(4);

参数4经过宏替换并字符串化之后,就成了:

printf(“the no. ” “4″ “,is”);

由于相邻的字符串会自动被连接,所以,它最终相当于:

printf(“the no. 4 ,is”);

由此 我们可以在 gcc 下试一下:

[root@localhost ~]# gcc -E –o test test.c
[root@localhost ~]# cat test
# 1 “test1.c”
# 1 “<built-in>”
# 1 “<command line>”
# 1 “test1.c”

int main()
{
      int data5=100;
      printf( “data ” “5″” = %d\n “, data5 );
      return 0;
}

这下就比较清楚了吧!

呵呵,其实C语言几十年不衰,还是有原因的,他有很经典的地方。很值得我们深入的研究它!

分类: Linux专区, 编程 标签:

由腾讯笔试题想到的–ELFHash分析

2010年8月3日 小卢 4 条评论
在一个cache系统中,需要实现一个域名白名单,域名为下列数据:
www.qq.com、www.baidu.com、sohu.com 等
该白名单需要在程序启动时加载一次,主要执行查询操作。请设计一个数据结构和相应的初始化查询函数,使得检索尽可能的快。(不能使用stl::map,等等key-value刑类库)。
我们可以看到,该题目提出了字符串的快速查找,并且只加载一次。使用Hash比较好。
我们可能首先就是想到使用 C++ 中的 MAP ,题目中给出了不允许使用MAP,那么肯定第二选择就是使用Berkeley DB (DB)这种的文件数据库了,但是题目中明显提出不允许使用key-value类型库。
我们思考Berkeley DB (DB)的原理可以晓得,这个就是一个Hash的过程,map其实也是hash的思想。
自己设计一个hash系统咯。冲突处理…
字符串hash可能就想到使用ELFhash算法,主要分析下ELFHash算法。
ELFhash函数在UNIX系统V 版本4中的“可执行链接格式”( Executable and Linking Format,即ELF )中会用到,ELF文件格式用于存储可执行文件与目标文件。ELFhash函数是对字符串的散列。它对于长字符串和短字符串都很有效,字符串中每个字符都有同样的作用,它巧妙地对字符的ASCII编码值进行计算,ELFhash函数对于能够比较均匀地把字符串分布在散列表中。
这些函数使用位运算使得每一个字符都对最后的函数值产生影响。

// ELF Hash Function

unsigned int ELFHash(char *str)

{

 unsigned int hash = 0;

 unsigned int x = 0;

 

 while (*str)

 {

 hash = (hash << 4) + (*str++);//hash左移4位,当前字符ASCII存入hash低四位。 

if ((x = hash & 0xF0000000L) != 0)

{//如果最高的四位不为0,则说明字符多余7个,如果不处理,再加第九个字符时,第一个字符会被移出,因此要有如下处理。

//该处理,如果对于字符串(a-z 或者A-Z)就会仅仅影响5-8位,否则会影响5-31位,因为C语言使用的算数移位

hash ^= (x >> 24);

//清空28-31位。

hash &= ~x;

}

}

//返回一个符号位为0的数,即丢弃最高位,以免函数外产生影响。(我们可以考虑,如果只有字符,符号位不可能为负)

return (hash & 0×7FFFFFFF);

}

 


 

分类: Linux专区, 算法讨论 标签:

MySQL中找到SQL耗时瓶颈,(利刀SHOW PROFILE)各个击破

2010年4月27日 小卢 10 条评论

最近做的数据量上升了,部分表到了上千条的数据,那个速度真是惨不忍睹啊,一个字“慢”!
分析下SQL的问题吧!手动分析,只能看到网上说的那些优化方法。但是瓶颈在那里呢?可以使用explain 的方式解决,但是还是感觉explain  不够详细。

MySQL5.0.37版本以上支持了,profiling ,据说是Jeremy Cole捐献给MySQL社区版本,呵呵。就说说他的使用吧!

profiling 功能可以了解到sql语句消耗资源的更详细的信息。

show profile 的格式如下:

SHOW PROFILE [type [, type] … ]
    [FOR QUERY n]
    [LIMIT row_count [OFFSET offset]]

type:
    ALL
  | BLOCK IO
  | CONTEXT SWITCHES
  | CPU
  | IPC
  | MEMORY
  | PAGE FAULTS
  | SOURCE
  | SWAPS

该方式默认是关闭的。
可以通过以下语句查看
mysql>select @@profiling;
+————-+
| @@profiling |
+————-+
|           0 |
+————-+
1 row in set (0.00 sec)

打开功能

mysql>set profiling=1;

执行需要测试的sql 语句:

 select inet_ntoa(visit_net) visit_net,sum(totalbytes) as totalbytes,sum(inbytes) as inbytes,sum(totalbytes)-sum(inbytes) as outbytes from
      ( select * from businessflow where userid=9 ) aa
  group by visit_net order by totalbytes DESC limit 0,3

mysql> show profiles\G;

通过指定的Query_ID 来查询指定的sql语句的执行信息:

mysql> show profile for query 1;

+——————————–+———-+
| Status                         | Duration |
+——————————–+———-+
| starting                       | 0.000021 |
| checking query cache for query | 0.000085 |
| Opening tables                 | 0.000036 |
| System lock                    | 0.000007 |
| Table lock                     | 0.000071 |
| optimizing                     | 0.000012 |
| statistics                     | 0.000013 |
| preparing                      | 0.000013 |
| executing                      | 0.000005 |
| Sending data                   | 0.592819 |
| converting HEAP to MyISAM      | 0.026474 |
| Sending data                   | 0.215715 |
| init                           | 0.000029 |
| storing result in query cache  | 0.000012 |
| optimizing                     | 0.000005 |
| statistics                     | 0.000011 |
| preparing                      | 0.000008 |
| Creating tmp table             | 0.000038 |
| executing                      | 0.000004 |
| Copying to tmp table           | 0.235759 |
| converting HEAP to MyISAM      | 1.020230 |
| Copying to tmp table on disk   | 0.166174 |
| Sorting result                 | 0.056304 |
| Sending data                   | 0.000053 |
| end                            | 0.000004 |
| removing tmp table             | 0.003539 |
| end                            | 0.000008 |
| query end                      | 0.000004 |
| freeing items                  | 0.000036 |
| removing tmp table             | 0.004107 |
| closing tables                 | 0.000009 |
| logging slow query             | 0.000004 |
| cleaning up                    | 0.000004 |
+——————————–+———-+
33 rows in set (0.00 sec)
mysql> show profile cpu for query 1;
+——————————–+———-+———-+————+
| Status                         | Duration | CPU_user | CPU_system |
+——————————–+———-+———-+————+
| starting                       | 0.000021 | 0.000000 |   0.000000 |
| checking query cache for query | 0.000085 | 0.000000 |   0.000000 |
| Opening tables                 | 0.000036 | 0.000000 |   0.000000 |
| System lock                    | 0.000007 | 0.000000 |   0.000000 |
| Table lock                     | 0.000071 | 0.000000 |   0.000000 |
| optimizing                     | 0.000012 | 0.000000 |   0.000000 |
| statistics                     | 0.000013 | 0.000000 |   0.000000 |
| preparing                      | 0.000013 | 0.000000 |   0.000000 |
| executing                      | 0.000005 | 0.000000 |   0.000000 |
| Sending data                   | 0.592819 | 0.592037 |   0.000000 |
| converting HEAP to MyISAM      | 0.026474 | 0.000000 |   0.020002 |
| Sending data                   | 0.215715 | 0.212014 |   0.008000 |
| init                           | 0.000029 | 0.000000 |   0.000000 |
| storing result in query cache  | 0.000012 | 0.000000 |   0.000000 |
| optimizing                     | 0.000005 | 0.000000 |   0.000000 |
| statistics                     | 0.000011 | 0.000000 |   0.000000 |
| preparing                      | 0.000008 | 0.000000 |   0.000000 |
| Creating tmp table             | 0.000038 | 0.000000 |   0.000000 |
| executing                      | 0.000004 | 0.000000 |   0.000000 |
| Copying to tmp table           | 0.235759 | 0.240015 |   0.000000 |
| converting HEAP to MyISAM      | 1.020230 | 0.988061 |   0.032002 |
| Copying to tmp table on disk   | 0.166174 | 0.160010 |   0.000000 |
| Sorting result                 | 0.056304 | 0.052004 |   0.008001 |
| Sending data                   | 0.000053 | 0.000000 |   0.000000 |
| end                            | 0.000004 | 0.000000 |   0.000000 |
| removing tmp table             | 0.003539 | 0.000000 |   0.000000 |
| end                            | 0.000008 | 0.000000 |   0.000000 |
| query end                      | 0.000004 | 0.000000 |   0.000000 |
| freeing items                  | 0.000036 | 0.000000 |   0.000000 |
| removing tmp table             | 0.004107 | 0.000000 |   0.008000 |
| closing tables                 | 0.000009 | 0.000000 |   0.000000 |
| logging slow query             | 0.000004 | 0.000000 |   0.000000 |
| cleaning up                    | 0.000004 | 0.000000 |   0.000000 |
+——————————–+———-+———-+————+
33 rows in set (0.00 sec)

从上上面可以看到,

| Sending data                   | 0.592819 |
| converting HEAP to MyISAM      | 0.026474 |
| Sending data                   | 0.215715 |

| Copying to tmp table           | 0.235759 |
| converting HEAP to MyISAM      | 1.020230 |
| Copying to tmp table on disk   | 0.166174 |

以上几项 耗时较长,所以考虑把该表转换为MyISAM 以供查询提高速度。并且提高的值

测试完毕以后 ,关闭参数:

mysql> set profiling=0

再次打开程序,发现等待速度降低。问题有所好转。OK!
参考:http://dev.mysql.com/doc/refman/5.0/en/show-profiles.html

分类: Linux专区, mysql 标签: ,

windows xp下 grub硬盘引导 Ubuntu 9.10

2010年4月17日 小卢 2 条评论

         以前一直在用rhel5的系统,习惯了KDE的界面,最近想换下,网上Ubuntu炒的很热,很想试一下,但是实验室配的电脑没有光驱,而且自己也懒得去刻盘了,还是试一下硬盘安装吧!看到用wubi.exe就可以安装,但是百度了一下,网上说这种安装方式有点虚拟的意思,装到某个文件夹下了,感觉这样不爽,还是自己动手把它装到硬盘分区上吧!呵呵,搜资料、安装,OK,写个记录。

 
1)下载karmic-desktop-i386.iso

地址: http://cdimage.ubuntu.com/daily-live/current/

2)用UltraISO等虚拟光驱工具,从karmic-desktop-i386.iso的casper文件夹内提取vmlinuz和initrd.lz到e盘根目录(我用的E盘)
3)karmic-desktop-i386.iso 也要放在D盘根目录,改名ubuntu-9.10-desktop-i386.iso
4)安装WINGRB软件。
打开 wingrub程序,选择 tools菜单,然后点击 install grub ,直接点一下Boot From Grub Partion 就行,然后点击,右边的下接框;选择要安装在哪个分区中,然后按最下边[install]; 这样grub就安装好了;他的配置文件在 c:\boot\grub\中 (隐藏受保护文件),配置文件是c:\boot\grub\menu.lst ,或在c:\Grub\MENU.LST(也就是WINGRUB的安装目录中)这个配置文件起到决定性作用;所以我们一定要写好;语法和Linux中的没有区别;是一样的。
5)修改menu.list。

 

win会有一个引导,这个我们不管他。
title Windows at (hd0,0)
root (hd0,0)
chainloader +1

下面添加自己 引导

title Ubuntu9.10 (Enter to set up)
root (hd0,5)
kernel (hd0,5)/vmlinuz boot=casper noacpi iso-scan/filename=/ubuntu-9.10-desktop-i386.iso ro quiet splash –
label check live-install
initrd (hd0,5)/initrd.lz

注意:(hd0,5)是 e盘的意思,你的解压文件在那个盘。不同的盘有不同的编号。打开wingrub,点tools =》partioinlist (分区列表),这里能了解到机器的分区对应的编号。
6) 重启安装

     进如live cd 桌面,剩下来的和光盘安装方法一样了,参照论坛的其它关于9.10 或 8.10的介绍就可以了,再此不想雷叙。
新手注意:不要忘记bootini及grldr,硬盘安装需要windows下删除一个分区,否则,ubuntu的安装程序认不到硬盘分区,关于(hd0,5)等一些基本分区知识,。
      用grub硬盘引导 进入livcd界面后,如要选择安装ubuntu到分区,首先必需要打开终端输入 sudo umount -l isodevice
,否则,安装程序会无法分区,或到安装进度达百分之95左右时忽然提示,“GRUB无法………这是一个至命的错误“,这时会很惨,已经无法后退,千万不要重启,如果重启,就死定了,重启后,ubuntu没装成,windows xp也启动不了,只能找一张ubuntu的光盘来装了!

分类: Linux专区 标签: , ,

字符串和时间转换time_t

2010年4月15日 小卢 1 条评论

1.指定time_t类型的时间,格式化为YYYYMMDDHH24MISS型的字符串

void timeToSting(time_t time1, char *szTime)
{
        struct tm tm1;
#ifdef WIN32
        tm1 = *localtime(&time1);
#else
        localtime_r(&time1, &tm1 );
#endif
        sprintf( szTime, "%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d",
                     tm1.tm_year+1900, tm1.tm_mon+1, tm1.tm_mday,
                         tm1.tm_hour, tm1.tm_min,tm1.tm_sec);
}

2.指定YYYY-MM-DD HH24:MI:SS型的时间,格式化为time_t型的时间

time_t stingToTime(char * szTime)
{
        struct tm tm1;
        time_t time1;
        sscanf(szTime, "%4d-%2d-%2d %2d:%2d:%2d",   
                     &tm1.tm_year,
                     &tm1.tm_mon,
                     &tm1.tm_mday,
                     &tm1.tm_hour,
                     &tm1.tm_min,
                     &tm1.tm_sec);             
        tm1.tm_year -= 1900;
        tm1.tm_mon --;
        tm1.tm_isdst=-1;  
        time1 = mktime(&tm1);
        return time1;
}
分类: Linux专区 标签: ,

Putty使用显示中文&mysqldump导出存储过程

2010年4月14日 小卢 1 条评论

      管理自己的服务器,或者网站后台,我们不免用的SSH登陆,说道SSH 可能有很多可以用的客户端 ,但是目前最好用的(个人认为)还是 Putty,用SSH登上Linux或者UNIX管理,还是很方便的,因为SSH 轻巧、便利。

      在win下登陆上来怎么显示中文呢?可能很多客户端都做不到,目前百度出来的只有Putty 能支持,putty默认也是不支持的,但是你可以设置一下,让你的putty,支持中文。

   这个问题其实很早都遇到了,懒得写下来,最近发现师弟们用Putty的时候都遇到了这个问题,每次都要讲一遍,还是就把它写成文档,记录下来,这样方便,呵呵。

点开基本上就是这个样子了,呵呵

Windows -> Appearance-> change->Fixedsys字体

如下图

设置之后,更改

要Putty支持中文,我们设置一下,如下图

点击Translation ->Received data assumed to be in which character set ->utf-8

这样就OK

设置好了以后,最好 save 一下,这样就可以“一劳永逸”了。

 

今天还遇到一个事情,昨天用mysqldump导出的文件,没有存储过程,一下存储过程就丢了,惨那,还好有些备份。导出存储过程要加参数:

mysqldump -uname -ppwd -R  database > name.sql
-R 可以dump出存储过程,对mysql5之后出来的存储过程备份很有用

mysql “log-bin”引起的硬盘120G文件

2010年4月12日 小卢 7 条评论

这两天在做数据的汇总与统计,统计去年12月份到现在的数据,数据全部以小时暂存到了文件里面,每个文件都有几百兆,算起来每个文件有接近十万条记录,程序做了两天周一回来发现只做了十几个文件,这些速度太慢了。然后想到,把表升级到内存表来做汇总。汇总完以后分类存到硬盘。这样看起来速度快了,很多…

但是今天早上起来本来想着肯定是要处理了几十个,结果来了一看,杯具了:数据库提示提示硬盘满了!
LOG:
Insert flow error: Disk is full writing ‘./mysql-bin.000127′ (Errcode: 28). Waiting for someone to free space… (Expect up to 60 secs delay for server to continue after freeing disk space)

有220G的硬盘怎么就满了呢?是数据文件太多了?
查看了下,发现home 占用了接近80G 空间。

[root@localhost ~]# du -h –max-depth=1 /home
78G     /home

   那么文件会是跑到哪里去了呢?
   一个邪恶的念头突然蹦出来了:不是服务器被攻击了吧?黑客用我们做了文件服务器?那样可就惨了…

   一个一个查,最后定位到了/var/lib/mysql/下,哦!突然想起来了,是不是数据库太大了,文件太多了?数据库记录是比较多,但是也不至于有120G吧?百度一下,网上说了,mysql数据库记录输入删

       掉以后,MySQL没有自动释放硬盘空间,而是自己管理已经向操作系统申请的空间,可以通过optimize table语法或alter table TableName engine=****来实现空间的释放。

当表的记录被删除时,数据文件并不会即时释放,但当有新记录写入时,数据文件也不一定会增加,只有当新写入的数据量超过了删除的数
据量时,数据文件的大小才会增加。原来mysql会自行利用逻辑上被释放的空间!
申请之后不再主动释放,自行内部管理,除非进行optimize table

      我们的MySQl版本是 Server version: 5.1.34-community-log MySQL Community Server,运用optimize table 出现错误:

Table does not support optimize, doing recreate + analyze instead

看到MySQL管网对optimize语法有详细的说明:

You can makeOPTIMIZE TABLE work on other storage engines by starting mysqld with the –skip-new or –safe-mode option. In this case, OPTIMIZE TABLE is just mapped to ALTER TABLE.

  上面是说要求我们在启动的时候指定–skip-new或者–safe-mode选项来支持optimize功能。
 马上添加 添加选项启动,问题解决。
硬盘有所减少,但是还有大量空间未释放。怎么回事呢?注意到/var/lib/mysql/有很多“mysql-bin.000XXX的文件,才发现是文件mysql 日志惹的祸。因为程序已经实现备份,所以就把log删掉

mysql>reset master; (清除日志文件)

屏蔽 log-bin

在/etc/my.cnf 下修改

log-bin=mysql-bin

为注释状态,重启Mysql!
问题解决!释放了120G的空间…

参考信息

有时候发现mysql-bin.000001、mysql- bin.000002等文件占用了空间,那么这些文件是干吗的?这是数据库的操作日志,例如UPDATE一个表,或者DELETE一些数据,即使该语句没 有匹配的数据,这个命令也会存储到日志文件中,还包括每个语句执行的时间,也会记录进去的。

这样做主要有以下两个目的:
1:数据 恢复
如果你的数据库出问题了,而你之前有过备份,那么可以看日志文件,找出是哪个命令导致你的数据库出问题了,想办法挽回损失。
2:主从 服务器之间同步数据
主服务器上所有的操作都在记录日志中,从服务器可以根据该日志来进行,以确保两个同步。

处理方法分两种情况:
1: 只有一个mysql服务器,那么可以简单的注释掉这个选项就行了。
vi /etc/my.cnf把里面的log-bin这一行注释掉,重启mysql服务即可。
2:如果你的环境是主从服务器,那么就需要做以下操作了。
A: 在每个从属服务器上,使用SHOW SLAVE STATUS来检查它正在读取哪个日志。
B:使用SHOW MASTER LOGS获得主服务器上的一系列日志。
C:在所有的从属服务器中判定最早的日志,这个是目标日志,如果所有的从属服务器是更新的,就是清单上的最 后一个日志。
D:清理所有的日志,但是不包括目标日志,因为从服务器还要跟它同步。
清理日志方法为:
PURGE MASTER LOGS TO ‘mysql-bin.010′;
PURGE MASTER LOGS BEFORE ‘2008-12-19 21:00:00′;

如果你确定从服务器已经同步过了,跟主服务器一样了,那么可以直接RESET MASTER将这些文件删除。

PHP Optimization by PHP Speedy PHP Optimization by PHP Speedy