存档:2008年十一月

我拿什么来纪念那些日子

十一月 29, 2008 | 心情杂记 | RSS 2.0

上一年得大概这个时间,一个人孤身来到北京,心里充满惊奇,期待,因为我终于可以走出校门,而且可以自己出来工作了,当时没有感觉到对学校得留恋。刚来到北京得日子,住了地下室一个月,那时候天气还很冷,手里也没多少钱,没好意思和家里人要,看在学校给别人 做网站挣了点小钱。地下室一个月好像400多一点,然后买什么东西都是特别的节省。也是那么得艰苦。
还好我顺利的上班了,经理人很好,而且待我还好,很快熟悉了工作。后来就是女朋友过来了,顺便我介绍了一个同学到公司。在12月份多得时候回了一次学校,毕业信息采集,还好,同学们都凑齐了,留影了,那时候还想,到6月份回学校一定玩个够,喝个够,以纪念我这段青春的岁月,四年得大学。尽情的放纵,尽情得挥洒。
然后就是回北京工作,过年,回来后抓住就要转成正式工的机会,我跳槽了。跳了一家能专业互联网的公司。
不过很不幸由于工作忙,所以到6月多回家的时候,学校已经没剩下多少人了,只有和仅剩下的几个兄弟,每天晚上出去喝酒。淡淡的悲伤。曾经一段时间埋在那段回忆了,看到一个个兄弟,哥们,即将各奔前程,心里真是一万个难受。还好在北京有有几个朋友。逝去的岁月令我心痛,同时也华为美好得回忆留在心中。愿一切过的回更好。并依此文激励自己努力。永远要记住,身体是革命的本钱,知识是革命的动力。

没有评论 »

【转】unicode、utf-8、ansi的故事

十一月 28, 2008 | 数据结构算法, 软件工程/编程技巧/设计模式 | RSS 2.0

快下班时,爱问问题的小朋友Nico又问了一个问题:”sqlserver里面有char和nchar,那个n据说是指unicode的数据,这个是什么意思。”并不是所有简单的问题都很容易回答,就像这个问题一样。于是我答应专门写一篇BLOG来从头讲讲编码的故事。那么就让我们找个草堆坐下,先抽口烟,看看夜晚天空上的银河,然后想一想要从哪里开始讲起。嗯,也许这样开始比较好……

很久很久以前,有一群人,他们决定用8个可以开合的晶体管来组合成不同的状态,以表示世界上的万物。他们看到8个开关状态是好的,于是他们把这称为”字节”。再后来,他们又做了一些可以处理这些字节的机器,机器开动了,可以用字节来组合出很多状态,状态开始变来变去。他们看到这样是好的,于是它们就这机器称为”计算机”。

开始计算机只在美国用。八位的字节一共可以组合出256(2的8次方)种不同的状态。他们把其中的编号从0开始的32种状态分别规定了特殊的用途,一但终端、打印机遇上约定好的这些字节被传过来时,就要做一些约定的动作。遇上00×10,终端就换行,遇上0×07, 终端就向人们嘟嘟叫,例好遇上0×1b,打印机就打印反白的字,或者终端就用彩色显示字母。他们看到这样很好,于是就把这些0×20以下的字节状态称为”控制码”。

他们又把所有的空格、标点符号、数字、大小写字母分别用连续的字节状态表示,一直编到了第127号,这样计算机就可以用不同字节来存储英语的文字了。大家看到这样,都感觉很好,于是大家都把这个方案叫做 ANSI 的”Ascii”编码(American Standard Code forInformation Interchange,美国信息互换标准代码)。当时世界上所有的计算机都用同样的ASCII方案来保存英文文字。

后来,就像建造巴比伦塔一样,世界各地的都开始使用计算机,但是很多国家用的不是英文,他们的字母里有许多是ASCII里没有的,为了可以在计算机保存他们的文字,他们决定采用127号之后的空位来表示这些新的字母、符号,还加入了很多画表格时需要用下到的横线、竖线、交叉等形状,一直把序号编到了最后一个状态255。从128到255这一页的字符集被称”扩展字符集”。从此之后,贪婪的人类再没有新的状态可以用了,美帝国主义可能没有想到还有第三世界国家的人们也希望可以用到计算机吧!

等中国人们得到计算机时,已经没有可以利用的字节状态来表示汉字,况且有6000多个常用汉字需要保存呢。但是这难不倒智慧的中国人民,我们不客气地把那些127号之后的奇异符号们直接取消掉,规定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(他称之为高字节)从0xA1用到0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的字母、日文的假名们都编进去了,连在 ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的”全角”字符,而原来在127号以下的那些就叫”半角”字符了。

中国人民看到这样很不错,于是就把这种汉字方案叫做 “GB2312″。GB2312 是对 ASCII的中文扩展。但是中国的汉字太多了,我们很快就就发现有许多人的人名没有办法在这里打出来,特别是某些很会麻烦别人的国家领导人。于是我们不得不继续把GB2312 没有用到的码位找出来老实不客气地用上。

后来还是不够用,于是干脆不再要求低字节一定是127号之后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容。结果扩展之后的编码方案被称为 GBK 标准,GBK 包括了 GB2312的所有内容,同时又增加了近20000个新的汉字(包括繁体字)和符号。后来少数民族也要用电脑了,于是我们再扩展,又加了几千个新的少数民族的字,GBK 扩成了 GB18030。从此之后,中华民族的文化就可以在计算机时代中传承了。

中国的程序员们看到这一系列汉字编码的标准是好的,于是通称他们叫做 “DBCS”(Double Byte Charecter Set双字节字符集),也叫做ANSI字符集。在ANSI/DBCS系列标准里,最大的特点是两字节长的汉字字符和一字节长的英文字符并存于同一套编码方案里,因此他们写的程序为了支持中文处理,必须要注意字串里的每一个字节的值,如果这个值是大于127的,那么就认为一个双字节字符集里的字符出现了。那时候凡是受过加持,会编程的计算机僧侣们都要每天念下面这个咒语数百遍:”一个汉字算两个英文字符!一个汉字算两个英文字符……”

因为当时各个国家都像中国这样搞出一套自己的编码标准,结果互相之间谁也不懂谁的编码,谁也不支持别人的编码,连大陆和台湾这样只相隔了150海里,使用着同一种语言的兄弟地区,也分别采用了不同的 ANSI/DBCS编码方案——当时的中国人想让电脑显示汉字,就必须装上一个”汉字系统”,专门用来处理汉字的显示、输入的问题,但是那个台湾的愚昧封建人士写的算命程序就必须加装另一套支持 BIG5编码的什么”倚天汉字系统”才可以用,装错了字符系统,显示就会乱了套!这怎么办?而且世界民族之林中还有那些一时用不上电脑的穷苦人民,他们的文字又怎么办?真是计算机的巴比伦塔命题啊!

正在这时,大天使加百列及时出现了——一个叫 ISO(国际标谁化组织)的国际组织决定着手解决这个问题。他们采用的方法很简单:废了所有的地区性编码方案,重新搞一个包括了地球上所有文化、所有字母和符号的编码!他们打算叫它”Universal Multiple-Octet Coded Character Set”,简称 UCS,俗称“UNICODE”。

UNICODE 开始制订时,计算机的存储器容量极大地发展了,空间再也不成为问题了。于是 ISO就直接规定必须用两个字节,也就是16位来统一表示所有的字符,对于ascii里的那些“半角”字符,UNICODE包持其原编码不变,只是将其长度由原来的8位扩展为16位,而其他文化和语言的字符则全部重新统一编码。由于”半角”英文符号只需要用到低8位,所以其高8位永远是0,因此这种大气的方案在保存英文文本时会多浪费一倍的空间。

这时候,从旧社会里走过来的程序员开始发现一个奇怪的现象:他们的strlen函数靠不住了,一个汉字不再是相当于两个字符了,而是一个!是的,从UNICODE开始,无论是半角的英文字母,还是全角的汉字,它们都是统一的”一个字符”!同时,也都是统一的”两个字节”,请注意”字符”和”字节”两个术语的不同,“字节”是一个8位的物理存贮单元,而“字符”则是一个文化相关的符号。在UNICODE中,一个字符就是两个字节。一个汉字算两个英文字符的时代已经快过去了。

从前多种字符集存在时,那些做多语言软件的公司遇上过很大麻烦,他们为了在不同的国家销售同一套软件,就不得不在区域化软件时也加持那个双字节字符集咒语,不仅要处处小心不要搞错,还要把软件中的文字在不同的字符集中转来转去。UNICODE 对于他们来说是一个很好的一揽子解决方案,于是从Windows NT 开始,MS 趁机把它们的操作系统改了一遍,把所有的核心代码都改成了用 UNICODE方式工作的版本,从这时开始,WINDOWS 系统终于无需要加装各种本土语言系统,就可以显示全世界上所有文化的字符了。

但是,UNICODE 在制订时没有考虑与任何一种现有的编码方案保持兼容,这使得 GBK 与 UNICODE 在汉字的内码编排上完全是不一样的,没有一种简单的算术方法可以把文本内容从 UNICODE 编码和另一种编码进行转换,这种转换必须通过查表来进行。

如前所述,UNICODE是用两个字节来表示为一个字符,他总共可以组合出65535不同的字符,这大概已经可以覆盖世界上所有文化的符号。如果还不够也没有关系,ISO已经准备了UCS-4方案,说简单了就是四个字节来表示一个字符,这样我们就可以组合出21亿个不同的字符出来(最高位有其他用途),这大概可以用到银河联邦成立那一天吧!

UNICODE 来到时,一起到来的还有计算机网络的兴起,UNICODE 如何在网络上传输也是一个必须考虑的问题,于是面向传输的众多UTF(UCS Transfer Format)标准出现了,顾名思义,UTF8就是每次8个位传输数据,而UTF16就是每次16个位,只不过为了传输时的可靠性,从UNICODE到UTF时并不是直接的对应,而是要过一些算法和规则来转换。

受到过网络编程加持的计算机僧侣们都知道,在网络里传递信息时有一个很重要的问题,就是对于数据高低位的解读方式,一些计算机是采用低位先发送的方法,例如我们PC机采用的 INTEL架构,而另一些是采用高位先发送的方式,在网络中交换数据时,为了核对双方对于高低位的认识是否是一致的,采用了一种很简便的方法,就是在文本流的开始时向对方发送一个标志符——如果之后的文本是高位在先,那就发送”FEFF”,反之,则发送”FFFE”。不信你可以用二进制方式打开一个UTF-X格式的文件,看看开头两个字节是不是这两个字节?

讲到这里,我们再顺便说说一个很著名的奇怪现象:当你在 windows的记事本里新建一个文件,输入”联通”两个字之后,保存,关闭,然后再次打开,你会发现这两个字已经消失了,代之的是几个乱码!呵呵,有人说这就是联通之所以拼不过移动的原因。其实这是因为GB2312编码与UTF-8编码产生了编码冲撞的原因。

从网上引来一段从UNICODE到UTF-8的转换规则:
Unicode              UTF-8
0000 – 007F        0xxxxxxx
0080 – 07FF        110xxxxx 10xxxxxx
0800 – FFFF        1110xxxx 10xxxxxx 10xxxxxx

例如”汉”字的Unicode编码是6C49。6C49在0800-FFFF之间,所以要用3字节模板:1110xxxx 10xxxxxx10xxxxxx。将6C49写成二进制是:0110 1100 0100 1001,将这个比特流按三字节模板的分段方法分为0110 110001001001,依次代替模板中的x,得到:1110-0110 10-110001 10-001001,即E6 B1 89,这就是其UTF8的编码。

而当你新建一个文本文件时,记事本的编码默认是ANSI, 如果你在ANSI的编码输入汉字,那么他实际就是GB系列的编码方式,在这种编码下,”联通”的内码是:
c1 1100 0001
aa 1010 1010
cd 1100 1101
a8 1010 1000

注意到了吗?第一二个字节、第三四个字节的起始部分的都是”110″和”10″,正好与UTF8规则里的两字节模板是一致的,于是再次打开记事本时,记事本就误认为这是一个UTF8编码的文件,让我们把第一个字节的110和第二个字节的10去掉,我们就得到了”00001101010″,再把各位对齐,补上前导的0,就得到了”0000 0000 01101010″,不好意思,这是UNICODE的006A,也就是小写的字母”j”,而之后的两字节用UTF8解码之后是0368,这个字符什么也不是。这就是只有”联通”两个字的文件没有办法在记事本里正常显示的原因。

而如果你在”联通”之后多输入几个字,其他的字的编码不见得又恰好是110和10开始的字节,这样再次打开时,记事本就不会坚持这是一个utf8编码的文件,而会用ANSI的方式解读之,这时乱码又不出现了。

没有评论 »

七步助你走向成功

十一月 28, 2008 | 心情杂记 | RSS 2.0

   一、不轻言退缩

    二、不停学习,不断修正。

    三、坐言起行,立即动手,从小事做起。

    为什么看到机会却没有抓住,是因为我们在犹豫:用什么方法更好啊,是不是还有更好的机会啊,或者这是不是机会啊。

    说狼在森林里追兔子,兔子看到狼来了决定跑,它想,是先跳左腿,还是先跳右腿,是怎么跳好看一点,还没来得及想完,就被狼吃了。

    简单的事情简单做,复杂的事情简单做,简单的事情重复做等等,都是保证坐言起行效果的方法。

    四、尊重每一个人。

   我们一生会遇到很多人,经常打交道的人却很有限,他们可能只有50到100人甚至可能更少,但是每一个人都会给我们带来机会,每一个人都可能成为我们的客户,每个人都可能成为我们的朋友,因此我们对每一个人都应该是尊重的。只有时时刻刻把小我收起来,才能够让自己得到更大的成长。

    五、为常人难为之事

    这个世界上为什么这么多人碌碌无为、平庸一生,是因为他们有一个习惯思维,“我凭什么要这么做”,“别人怎么不做”,“我为什么要做”。

    有些事情、有些机会就像一层窗户纸,稍纵即逝,但有些机会就像表面看起来发烫,但实际上是常温状态的石子,只是红色的而已。

    六、保持饥饿感。

    我们要想有一个健康的身体,一个健康的事业前景,我们自己就必须有饥饿感,必须永不满足。在觉得日子不错的时候,稍微休息休息,享受享受人生乐趣就行了,此后需要赶紧爬起来奔跑。

    七、不与消极者交密友。

    如果一个人老是抱怨,动不动就说这不行,那不行,这不可为,那不可为,就少跟他打交道。我们的目标是提高我们自己,是超越我们自己,是让我们更加成功。从一个消极者身上基本学不到积极的东西。

    八、勇担责任

    这世界上机会很多,但为什么很多人不敢抓,有一个原因就是怕烫手。

    一个人在一个团队中间是因为敢于承担责任,才会获得信赖;是因为敢于承担责任,才能够显示价值;是因为敢于承担责任,才会让越来越多无能的人说反正有他扛着,我们就听他的就行了,让他领着我们干,这个人才有了独特的领导价值。

    是没有责任心的人在衬托有责任心的伟大,是他们在给有责任心的人以机会。如果想得到常人所得不到的满足和快乐,就要承担常人不愿承担的责任。

    九、事务分类、聚焦处理

    保持清醒头脑,形成对事务进行分类的习惯,并立即分解处理重要且紧急的事情,持续处理重要而不紧急的事情,见缝插针处理紧急而不重要的事情。

    十、处变不惊、胆大心细

    天塌下来我们可以缩着头,可以哭,可以藏,可以躲,但天还是要塌下来,所以惊也没用。

    就算天塌下来我们没有任何的方法,那我们也要先尝试扛着再说,先扛着我们才能冷静下来细细的去琢磨解决问题的方法

没有评论 »

简单代理服务器

十一月 28, 2008 | c/c++, linux | RSS 2.0

/*
** 编写:无可非议
** 来源:www.20CN.NET
** 注意:请注明转贴来源
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/stat.h>

int m_MainId = 0; //主进程ID
int m_ListenSocket = 0; //侦听套接字
char m_ConnectAddr[256] = {0}; //目标地址
char m_ConnectPort[256] = {0}; //目标端口

/*
** 函数名称: GetListenSocket
** 函数功能: 生成侦听套接字
** 传入参数: Port : 侦听端口
** 传出参数: 无
** 引用函数: 无
** 返回值 : 侦听套接字,为0时表示生成套接字失败,其他为套接字句柄
** 备注 : 无
*/
int GetListenSocket(int Port)
{
struct sockaddr_in m_LisAddr = {0};
int m_Socket = 0;
int m_AddrLen = sizeof(struct sockaddr_in);

//配置端口信息
m_LisAddr.sin_family = AF_INET;
m_LisAddr.sin_port = htons(Port);
m_LisAddr.sin_addr.s_addr = INADDR_ANY;

//创建套接字
if ((m_Socket = socket(AF_INET,SOCK_STREAM,0)) < 0 )
{
//创建套接字失败
return 0;
}

//绑定套接字
if(bind(m_Socket, (sockaddr*)&m_LisAddr , m_AddrLen) < 0 )
{
//绑定套接字失败
close(m_Socket);
return 0;
}

//侦听套接字
if(listen(m_Socket,5))
{
//侦听套接字失败
close(m_Socket);
return 0;
}

//侦听套接字生成成功
return m_Socket;
}

/*
** 函数名称: GetConnectSocket
** 函数功能: 生成连接套接字
** 传入参数: pServerAddr : 连接地址 pServerPort : 连接端口
** 传出参数: 无
** 引用函数: 无
** 返回值 : 连接套接字,为0时表示生成套接字失败,其他为套接字句柄
** 备注 : 无
*/
int GetConnectSocket(char* pServerAddr,char* pServerPort)
{
struct sockaddr_in m_ServerAddr = {0};
int m_AddrLen = sizeof(struct sockaddr_in);
int m_Socket = 0;

//初始化连接信息
m_ServerAddr.sin_addr.S_un.S_addr = inet_addr(pServerAddr);
m_ServerAddr.sin_port = htons(atoi(pServerPort));
m_ServerAddr.sin_family = AF_INET;

//创建发送套接字
m_Socket = socket(AF_INET,SOCK_STREAM,0);
if(m_Socket <= 0)
{
//失败
return NULL;
}

//连接客户计算机
if(connect(m_Socket,(sockaddr*)&m_ServerAddr,m_AddrLen) < 0 )
{
close(m_Socket);
return NULL;
}

//连接成功
return m_Socket;
}

/*
** 函数名称: TransSocket
** 函数功能: 完成套接字数据转发
** 传入参数: m_SendSocket : 发送套接字 m_RecvSocket : 接收套接字
** 传出参数: 无
** 引用函数: 无
** 返回值 : 无
** 备注 : 逆反完成全双工
*/
void TransSocket(int m_SendSocket,int m_RecvSocket)
{
char m_Buf[512 * 1024] = {0};
int ret = 0;
fd_set readset;
struct timeval tm = {0};
tm.tv_sec = 3600 * 24;

FD_ZERO(&readset);
FD_SET(m_RecvSocket,&readset);

while(1)
{
if((select(m_RecvSocket + 1,&readset,NULL,NULL,&tm)
<= 0))
{
//出错
break;
}
if(!FD_ISSET(m_RecvSocket,&readset)) continue;

ret = recv(m_RecvSocket,m_Buf,512 * 1024 – 1,0);
if(ret < 0)
{
//出错
break;
}
send(m_SendSocket,m_Buf,ret,0);
}
close(m_SendSocket);
close(m_RecvSocket);
}

/*
** 函数名称: SocketTrans
** 函数功能: 工作主函数,完成数据转发,新进程启动
** 传入参数: m_SendSocket : 发送套接字 m_RecvSocket : 接收套接字
** 传出参数: 无
** 引用函数: 无
** 返回值 : 无
** 备注 : 逆反完成全双工
*/
void SocketTrans()
{
struct sockaddr_in m_WorkAddr = {0};
int m_191Socket = 0;
int m_147socket = 0;
int m_WorkAddrLen = 0;

//开始任务执行
while(1)
{
//接受147的连接
m_WorkAddrLen = sizeof(struct sockaddr_in);
m_147socket = accept(m_ListenSocket,
(sockaddr*)&m_WorkAddr , &m_WorkAddrLen);

//检查套接字合法性
if(m_147socket < 0) continue;

//连接191
m_191Socket = GetConnectSocket(m_ConnectAddr,m_ConnectPort);
if(m_191Socket == NULL)
{
close(m_147socket);
continue;
}

int ret = fork();
if(ret < 0)
{
//建立新进程失败
printf(”致命错误,无法建立新进程!”);
fflush(stdout);
close(m_191Socket);
close(m_147socket);
break;
}
else if(ret == 0)
{
//关闭原来端口
close(m_ListenSocket);

//建立二次子进程,防止僵尸进程
ret = fork();
if(ret < 0)
{
close(m_191Socket);
close(m_147socket);
_exit(0);
}
else if(ret == 0)
{
//接收进程
TransSocket(m_191Socket,m_147socket);
_exit(0);
}
ret = fork();
if(ret < 0)
{
close(m_191Socket);
close(m_147socket);
_exit(0);
}
else if(ret == 0)
{
//发送进程
TransSocket(m_147socket,m_191Socket);
_exit(0);
}
close(m_191Socket);
close(m_147socket);
_exit(0);
}

//等待子线程结束
close(m_191Socket);
close(m_147socket);
waitpid(ret,NULL,0);
}
}

/*
** 函数名称: sig_usr
** 函数功能: 进程信号处理函数
** 传入参数: 无
** 传出参数: 无
** 引用函数: 无
** 返回值 : 无
** 备注 : 处理进程终止事件
*/
static void sig_usr(int signo)
{
close(m_ListenSocket);
if(m_MainId == getpid())
kill(0,SIGKILL);
exit(0);
}

static void sig_ign(int signo)
{
fprintf(stderr,”signal %d catched ,ignoring”,signo);
}

int daemon_init()
{
pid_t pid;
if((pid=fork())<0){
return -1;
}else if(pid!=0){
exit(0);
}
setsid();
umask(0);
return 0;
}

/*
** 函数名称: main
** 函数功能: 进程主函数
** 传入参数: 无
** 传出参数: 无
** 引用函数: MakeFilePath,GetMyInitInfo,SocketTrans
** 返回值 : 无
** 备注 : 为客户接收进程主函数
*/
int main(int argc,char* argv[])
{
//检查参数合法性
if(argc != 4)
{
printf(”格式:本地端口 目的地址 目的端口”);
fflush(stdout);
return 0;
}

daemon_init();

//登记信号事件
signal(SIGTERM,sig_usr);
signal(SIGINT,sig_usr);
signal(SIGQUIT,sig_usr);
signal(SIGPIPE,sig_ign);
signal(SIGALRM,sig_ign);
signal(SIGQUIT,sig_ign);
signal(SIGFPE,sig_ign);
signal(SIGILL,sig_ign);
signal(SIGPIPE,sig_ign);
signal(SIGSEGV,sig_ign);
signal(SIGTRAP,sig_ign);
signal(SIGTSTP,sig_ign);

//取参数
strcpy(m_ConnectAddr,argv[2]);
strcpy(m_ConnectPort,argv[3]);

//获取侦听套接字
m_ListenSocket = GetListenSocket(atoi(argv[1]));
if(m_ListenSocket == 0)
{
printf(”侦听端口[%s]失败!”,argv[1]);
fflush(stdout);
return 0;
}

m_MainId = getpid();
//启动文件接收侦听线程
SocketTrans();
close(m_ListenSocket);
return 0;
}

没有评论 »

innodb count 如何快

十一月 27, 2008 | mysql | RSS 2.0


Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 1904

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 1904

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 2257

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3206

Warning: implode() [function.implode]: Argument must be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3258

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3289

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3289

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3332

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3332

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3477

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3477

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 1904

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 1904

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 2257

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3206

Warning: implode() [function.implode]: Argument must be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3258

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3289

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3289

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3332

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3332

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3477

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3477

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 1904

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 1904

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 2257

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3206

Warning: implode() [function.implode]: Argument must be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3258

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3289

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3289

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3332

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3332

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3477

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3477

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 1904

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 1904

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 2257

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3206

Warning: implode() [function.implode]: Argument must be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3258

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3289

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3289

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3332

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3332

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3477

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3477

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 1904

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 1904

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 2257

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3206

Warning: implode() [function.implode]: Argument must be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3258

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3289

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3289

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3332

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3332

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3477

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3477

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 1904

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 1904

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 2257

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3206

Warning: implode() [function.implode]: Argument must be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3258

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3289

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3289

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3332

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3332

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3477

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3477

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 1904

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 1904

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 2257

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3206

Warning: implode() [function.implode]: Argument must be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3258

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3289

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3289

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3332

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3332

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3477

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3477

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 1904

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 1904

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 2257

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3206

Warning: implode() [function.implode]: Argument must be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3258

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3289

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3289

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3332

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3332

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3477

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3477

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 1904

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 1904

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 2257

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3206

Warning: implode() [function.implode]: Argument must be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3258

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3289

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3289

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3332

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3332

Warning: array_keys() [function.array-keys]: The first argument should be an array in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3477

Warning: Invalid argument supplied for foreach() in /home/liufabin66688/5aicha.com/wp-content/plugins/wp-syntax/geshi/geshi.php on line 3477

起因:在innodb表上做count(*)统计实在是太慢了,因此想办法看能不能再快点。
现象:先来看几个测试案例,如下
一、 sbtest 表上的测试

show create table sbtestG<br>*************************** 1. row ***************************<br>Table: sbtest<br>Create Table: CREATE TABLE `sbtest` (<br>`aid` bigint(20) unsigned NOT NULL auto_increment,<br>`id` int(10) unsigned NOT NULL default '0',<br>`k` int(10) unsigned NOT NULL default '0',<br>`c` char(120) NOT NULL default '',<br>`pad` char(60) NOT NULL default '',<br>PRIMARY KEY  (`aid`),<br>KEY `k` (`k`),<br>KEY `id` (`id`)<br>) ENGINE=InnoDB AUTO_INCREMENT=1000001 DEFAULT CHARSET=latin1<br><br>show index from sbtest;<br>+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+<br>| Table  | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |<br>+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+<br>| sbtest |          0 | PRIMARY  |            1 | aid         | A         |     1000099 |     NULL | NULL   |      | BTREE      |         |<br>| sbtest |          1 | k        |            1 | k           | A         |          18 |     NULL | NULL   |      | BTREE      |         |<br>| sbtest |          1 | id       |            1 | id          | A         |     1000099 |     NULL | NULL   |      | BTREE      |         |<br>+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

填充了 1000万条 记录。
1、 直接 count(*)

explain SELECT COUNT(*) FROM sbtest;<br>+----+-------------+--------+-------+---------------+---------+---------+------+---------+-------------+<br>| id | select_type | table  | type  | possible_keys | key     | key_len | ref  | rows    | Extra       |<br>+----+-------------+--------+-------+---------------+---------+---------+------+---------+-------------+<br>|  1 | SIMPLE      | sbtest | index | NULL          | PRIMARY | 8       | NULL | 1000099 | Using index |<br>+----+-------------+--------+-------+---------------+---------+---------+------+---------+-------------+<br>SELECT COUNT(*) FROM sbtest;<br>+----------+<br>| COUNT(*) |<br>+----------+<br>|  1000000 |<br>+----------+<br>1 row in set (1.42 sec)

可以看到,如果不加任何条件,那么优化器优先采用 primary key 来进行扫描。
2、count(*) 使用 primary key 字段做条件

explain SELECT COUNT(*) FROM sbtest WHERE aid&gt;=0;<br>+----+-------------+--------+-------+---------------+---------+---------+------+--------+--------------------------+<br>| id | select_type | table  | type  | possible_keys | key     | key_len | ref  | rows   | Extra                    |<br>+----+-------------+--------+-------+---------------+---------+---------+------+--------+--------------------------+<br>|  1 | SIMPLE      | sbtest | range | PRIMARY       | PRIMARY | 8       | NULL | 485600 | Using where; Using index |<br>+----+-------------+--------+-------+---------------+---------+---------+------+--------+--------------------------+<br>SELECT COUNT(*) FROM sbtest WHERE aid&gt;=0;<br>+----------+<br>| COUNT(*) |<br>+----------+<br>|  1000000 |<br>+----------+<br>1 row in set (1.39 sec)

可以看到,尽管优化器认为只需要扫描 485600 条记录(其实是索引),比刚才少多了,但其实仍然要做全表(索引)扫描。因此耗时和第一种相当。
3、 count(*) 使用 secondary index 字段做条件

explain SELECT COUNT(*) FROM sbtest WHERE id&gt;=0;<br>+----+-------------+--------+-------+---------------+------+---------+------+--------+--------------------------+<br>| id | select_type | table  | type  | possible_keys | key  | key_len | ref  | rows   | Extra                    |<br>+----+-------------+--------+-------+---------------+------+---------+------+--------+--------------------------+<br>|  1 | SIMPLE      | sbtest | range | id            | id   | 4       | NULL | 500049 | Using where; Using index |<br>+----+-------------+--------+-------+---------------+------+---------+------+--------+--------------------------+<br>SELECT COUNT(*) FROM sbtest WHERE id&gt;=0;<br>+----------+<br>| COUNT(*) |<br>+----------+<br>|  1000000 |<br>+----------+<br>1 row in set (0.43 sec)

可以看到,采用这种方式查询会非常快。
有人也许会问了,会不会是因为 id 字段的长度比 aid 字段的长度来的小,导致它扫描起来比较快呢?先不着急下结论,咱们来看看下面的测试例子。
二、 sbtest1 表上的测试

show create table sbtest1G<br>*************************** 1. row ***************************<br>Table: sbtest1<br>Create Table: CREATE TABLE `sbtest1` (<br>`aid` int(10) unsigned NOT NULL AUTO_INCREMENT,<br>`id` bigint(20) unsigned NOT NULL DEFAULT '0',<br>`k` int(10) unsigned NOT NULL DEFAULT '0',<br>`c` char(120) NOT NULL DEFAULT '',<br>`pad` char(60) NOT NULL DEFAULT '',<br>PRIMARY KEY (`aid`),<br>KEY `k` (`k`),<br>KEY `id` (`id`)<br>) ENGINE=InnoDB AUTO_INCREMENT=1000001 DEFAULT CHARSET=latin1<br>show index from sbtest1;<br>+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+<br>| Table   | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |<br>+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+<br>| sbtest1 |          0 | PRIMARY  |            1 | aid         | A         |     1000099 |     NULL | NULL   |      | BTREE      |         |<br>| sbtest1 |          1 | k        |            1 | k           | A         |          18 |     NULL | NULL   |      | BTREE      |         |<br>| sbtest1 |          1 | id       |            1 | id          | A         |     1000099 |     NULL | NULL   |      | BTREE      |         |<br>+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

这个表里,把 aid 和 id 的字段长度调换了一下,也填充了 1000万条 记录。
1、 直接 count(*)

explain SELECT COUNT(*) FROM sbtest1;<br>+----+-------------+---------+-------+---------------+---------+---------+------+---------+-------------+<br>| id | select_type | table   | type  | possible_keys | key     | key_len | ref  | rows    | Extra       |<br>+----+-------------+---------+-------+---------------+---------+---------+------+---------+-------------+<br>|  1 | SIMPLE      | sbtest1 | index | NULL          | PRIMARY | 4       | NULL | 1000099 | Using index |<br>+----+-------------+---------+-------+---------------+---------+---------+------+---------+-------------+<br>SELECT COUNT(*) FROM sbtest1;<br>+----------+<br>| COUNT(*) |<br>+----------+<br>|  1000000 |<br>+----------+<br>1 row in set (1.42 sec)

可以看到,如果不加任何条件,那么优化器优先采用 primary key 来进行扫描。
2、count(*) 使用 primary key 字段做条件

explain SELECT COUNT(*) FROM sbtest1 WHERE aid&gt;=0;<br>+----+-------------+---------+-------+---------------+---------+---------+------+--------+--------------------------+<br>| id | select_type | table   | type  | possible_keys | key     | key_len | ref  | rows   | Extra                    |<br>+----+-------------+---------+-------+---------------+---------+---------+------+--------+--------------------------+<br>|  1 | SIMPLE      | sbtest1 | range | PRIMARY       | PRIMARY | 4       | NULL | 316200 | Using where; Using index |<br>+----+-------------+---------+-------+---------------+---------+---------+------+--------+--------------------------+<br>1 row in set (0.00 sec)<br>SELECT COUNT(*) FROM sbtest1 WHERE aid&gt;=0;<br>+----------+<br>| COUNT(*) |<br>+----------+<br>|  1000000 |<br>+----------+<br>1 row in set (1.42 sec)

可以看到,尽管优化器认为只需要扫描 485600 条记录(其实是索引),比刚才少多了,但其实仍然要做全表(索引)扫描。因此耗时和第一种相当。
3、 count(*) 使用 secondary index 字段做条件

explain SELECT COUNT(*) FROM sbtest1 WHERE id&gt;=0;<br>+----+-------------+---------+-------+---------------+------+---------+------+--------+--------------------------+<br>| id | select_type | table   | type  | possible_keys | key  | key_len | ref  | rows   | Extra                    |<br>+----+-------------+---------+-------+---------------+------+---------+------+--------+--------------------------+<br>|  1 | SIMPLE      | sbtest1 | range | id            | id   | 8       | NULL | 500049 | Using where; Using index |<br>+----+-------------+---------+-------+---------------+------+---------+------+--------+--------------------------+<br>1 row in set (0.00 sec)<br>SELECT COUNT(*) FROM sbtest1 WHERE id&gt;=0;<br>+----------+<br>| COUNT(*) |<br>+----------+<br>|  1000000 |<br>+----------+<br>1 row in set (0.45 sec)

可以看到,采用这种方式查询会非常快。
上面的所有测试,均在 mysql 5.1.24 环境下通过,并且每次查询前都重启了 mysqld。
可以看到,把 aid 和 id 的长度调换之后,采用 secondary index 查询仍然是要比用 primary key查询来的快很多。看来主要不是字段长度引起的索引扫描快慢,而是采用 primary key 以及 secondary index引起的区别。那么,为什么用 secondary index 扫描反而比 primary key 扫描来的要快呢?我们就需要了解innodb的clustered indexsecondary index之间的区别了。
innodb的 clustered index 是把 primary key 以及 row data 保存在一起的,而 secondary index则是单独存放,然后有个指针指向 primary key。因此,需要进行 count(*) 统计表记录总数时,利用 secondaryindex 扫描起来,显然更快。而primary key则主要在扫描索引,同时要返回结果记录时的作用较大,例如:

SELECT * FROM sbtest WHERE aid = xxx;

那既然是使用 secondary index 会比 primary key 更快,为何优化器却优先选择 primary key 来扫描呢,Heikki Tuuri的回答是:

in the example table, the secondary index is inserted into in a perfect order! That is<br>very unusual. Normally the secondary index would be fragmented, causing random disk I/O,<br>and the scan would be slower than in the primary index.<br>I am changing this to a feature request: keep 'clustering ratio' statistics on a secondary<br>index and do the scan there if the order is almost the same as in the primary index. I<br>doubt this feature will ever be implemented, though.

没有评论 »

PHP代码的优与劣

十一月 27, 2008 | php | RSS 2.0

 我在SitePoint做面试官的时候一定会问的问题是:你认为PHP代码的优劣体现在哪里?因为这个问题可以让我大体知道应聘者是哪种类型的程序员,而不是单纯地考察他对PHP函数的掌握程度(这一点Zend的PHP认证做得不错,雅虎的PHP程序员面试题也属于此类)。

  重要的是,这个问题可以让我知道应聘者是否经历过这样的事情——从一个懒散程序员手中接过一段凌乱的代码进行重用,或者要帮助团队中的其他成员来处理这类事情。

  诚然,对于这个问题我自己并没有一个满意的答案,不过我知道哪些答案是我想听到的:

  优良的PHP代码应该是结构化的。大段的代码应该被分割整理成一个个函数或方法,而那些不气眼的小段代码则应该加上注释,以便日后清楚它们的用途。而且应该尽可能地把前台代码如HTML、CSS、Javascript等从程序中分离出来。PHP的面向对象编程特性可以很好地帮助程序员将代码整理有序。

  优良的PHP代码应该是规范化的。无论是为变量名和函数名设定命名规则,还是对一些会重复使用的过程如数据库操作和错误处理进行标准化,抑或是简单到规定好代码是怎样缩进的,这些规范化都可以让代码的可读性大大提高。

  优良的PHP代码应该是自适应的。PHP有许多特性如magic quotes和short tags,这些特性的打开和关闭会影响到程序的运行。所以,一个好的程序员应该在他的代码中加如适当的语句来使程序能够根据环境进行调整。

  优良的PHP代码应该是安全的。虽然PHP是一种高效、灵活的语言,没有固定的框架,但却把安全问题留给了程序员们。对潜在安全漏洞的深刻理解,如跨站脚本攻击(XSS)、跨站请求伪造(CSRF)、代码注入漏洞、字符编码循环漏洞等,对于今天的专业程序员来说是至关重要的。

  当应聘者在回答这些问题的时候,我就能清楚地知道是否该录用他。当然,有时程序员并不能很好地阐明这个问题,这时我们会让他们做一些PHP测试。测试中的许多问题表面上看起来非常简单,但这也给了应聘者们一个展现自我的机会,因为只要观察得仔细,就能找出问题。

  下面这一小段“劣质”的PHP代码是一道简化了的测试题。这种问题就像在问:你该怎样优化这段代码?

<?
echo(”<p>Search results for query: ” .
    $_GET['query'] . “.</p>”);
?>

  这段代码的主要问题在于它把用户提交的数据直接显示到了网页上,从而产生XSS漏洞。其实有很多方法可以填补这个漏洞。那么,什么代码是我们想要的呢?

<?
echo(”<p>Search results for query: ” .
    htmlspecialchars($_GET['query']) . “.</p>”);
?>

  这是最低要求。XSS漏洞用htmlspecialchars函数填补了,从而屏蔽了非法字符。

<?php  
if (isset($_GET['query']))  
{  
  echo ‘<p>Search results for query: ‘,  
      htmlspecialchars($_GET['query'], ENT_QUOTES), ‘.</p>’;  
}  
?> 

  能写出这样代码的人应该是我想要录用的人了。

  • <?被替换成了<?php,这样更符合XML规范。
  • 在输出$_GET['query']的值之前先判断它是否为空。
  • echo命令中多余的括号被去掉了。
  • 字符串用单引号限定,从而节省了PHP从字符串中搜索可替换的变量的时间。
  • 用逗号代替句号,节省了echo的时间。
  • 将ENT_QUOTES标识传递给htmlspecialchars函数,从而保证单引号也会被转义。虽然这并是最主要的,但也算是一个良好习惯。

  可惜的是,能给出这样让人满意答复的程序员少之又少。我们花了3个月的时间才招聘到让我们满意的程序员。

  那么,你会怎样回答文章开头提出的问题呢?你认为PHP代码的优劣体现在哪里?你认为一个PHP程序员还应具有哪些品质

没有评论 »

二进制文件

十一月 27, 2008 | linux, 数据结构算法 | RSS 2.0

也许这篇记录得太繁了. 不过还是有些有助理解的.

1. 流式文件:文件中的数据是一串字符,没有结构。

2. 文本文件是一种典型的顺序文件,其文件的逻辑结构又属于流式文件。特别的是,文本文件是指以ASCII码方式(也称文本方式)存储的文件,更确切地说,英文、数字等字符存储的是ASCII码,而汉字存储的是机内码。文本 文件中除了存储文件有效字符信息(包括能用ASCII码字符表示的回车、换行等信息)外,不能存储其他任何信息,因此文本文件不能存储声音、动画、图像、 视频等信息。

设某个文件的内容是下面一行文字: 中华人民共和国 CHINA 1949 如果以文本方式存储,机器中存储的是下面的代码(以十六进制表示,机器内部仍以二进制方式存储) D6 D0 BB AA C8 CB C3 F1 B9 B2 BA CD B9 FA 20 43

  48 49 4E 41 20 31 39 34 39 A1 A3 其中,D6D0BBAAC8CBC3F1B9B2BACDB9FA分别是中华人 民共和国ABCD” 七个汉字的机内码,20是空格的ASCII码,4348494E41分别是五个英文字母“CHINA”ASCII码,31393439 别是数字字符“1949”ASCII编码,A1A3是标点的机内码。 从上面可以看出,文本文件中信息是按单个字符编码存储的,如1949分别存储“1”“9” “4”“9”这四个字符的ASCII编码,如果将1949存储为079D(对应二进制为0000 0111 1001 1101,即十进制1949的等值数),则该文件一定不是文本文件。

文本文件是包含用户可读信息的文件。这些文件以ASCII码方式存储,可显示和打印。文本文件的行不能包括空字符(即码中的NULL),行的最大 长度(包括换行符在内)也不能超过(LINE_MAX)所定义的字节数。不过文本文件中并不限制使用除空字符以外的控制字符或其它不可打印字符。(二进制文件[此处指非文本文件]包含计算机可读信息的文件。二进制文件可以是可执行的文件,使系统根据其中的指令完成某项工作。命令和程序都是以可执行的而进制文件方式存储。二进制文件没有行的长度限制,也可包含空字符。)

3. 如果将存储的信息采用字符串方式来保存,那么称此类文件为文本文件(可以按字符显示)。将文件看作是由一个一个字节(byte) 组成的,那么文本文件中的每个字节的最高位都是0,也就是说文本文件使用了一个字节中的七位来表示所有的信息,而二进制文件则是将字节中的所有位都用上了。

如果将存储的信息严格按其在内存中的存储形式来保存,则称此类文件为二进制文件。二进制文件虽然也可在屏幕上显示,但其内容无法读懂。C系统在处理这些文件时,并不区分类型,都看成是字符流,按字节进行处理。输入输出字符流的开始和结束只由程序控制而不受物理符号(如回车符)的控制。因此也把这种文件称作流式文件。文本或字符文件代表慢速设备,而二进制文件代表可以大块数据操作的快速外设,二进制文件内容基本无意义,系统对它不加解释地传给调用者,解释由调用者负责.而对字符文件,系统把他理解为单字节的ASCII或多字节的UNICODE字符串,并且对其中的特殊字符(如回车等)加以特殊处理.所以同一个文件,可以使用不同类型的系统调用.

回车(CR)和换行(LF)符都是用来表示“下一行”的。而标准没有规定要使用哪一个。于是产生了三种不同的用法:

(1) Doswindows采用回车+换行(CR+LG)表示下一行

(2) UNIX采用换行符(LF)表示下一行

(3) MAC机采用回车符(CR)表示下一行。

当在不同的系统间传递文件,就要涉及格式的转换。

文本方式和二进制方式的最大区别在于文本方式对于换行符的理解不同

(1)DOS平台下,该字符会被展开成<CR>< LF>两个控制字符(相当于“”),在ASCII字符集下是 0DH,0AH

(2)UNIX平台下,仅仅是<LF>,不会展开。

(3)在二进制方式下,不管是什么平台,都是精确的<LF>

linux/unix 系统上,只有一种文件类型的系统,带b字母的模式和对应的不带b字母的模式是相同的。

关于EOF   EOF可以作为文本文件的结束标志,但不能作为二进制文件的结束符.feof函数既可以判断二进制文件,又可以判断文本文件. EOFWindows下是ctrl+zlinux下是ctrl+D.

第二个问题就是文件按照文本方式或者二进制方式打开,两者会有什么不同呢? 其实不管是二进制文件也好,还是文本文件也好,都是一连串的01,但是打开方式不同,对于这些01的处理也就不同。如果按照文本方式打开,在打开的时候会进行translate,将每个字节转换成ASCII码,而以按照二进制方式打开的话,则不会进行任何的translate

最后就是文本文件和二进制文件在编辑的时候,使用的方式也是不同的。譬如,你在记事本中进行文本编辑的时候,你进行编辑的最小单位是字节(byte);而对二进制文件进行编辑的话,最小单位则是位(bit),当然我们都不会直接通过手工的方式对二进制文件进行编辑了。

4. 输入码、区位码、国标码与机内码 (都是汉字的编码形式)

键盘是当前微机的主要输入设备, 输入码就是使用英文键盘输入汉字时的编码。

计算机只识别由01组成的代码,ASCII码是英文信息处理的标准编码,汉字信息处理也必须有一个统一的标准编码。我国国家标准局于19815月颁布 了《信息交换用汉字编码字符集——基本集》,代号为GB2312-80,共对6763个汉字和682个图形字符进行了编码,其编码原则为:汉字用两个字节 表示,每个字节用七位码(高位为0, 国家标准将汉字和图形符号排列在一个9494列的二维代码表中,;每两个字节分别用两位十进制编码,前字节的编 码称为区码,后字节的编码称为位码,此即区位码,如字在二维代码表中处于17区第3位,区位码即为“1703 ”

国标码并不等于区位码,它是由区位码稍作转换得到,其转换方法为:先将十进制区码和位码转换为十六进制的区码和位码,这样就得了一个与国标码有一个相对 位置差的代码,再将这个代码的第一个字节和第二个字节分别加上20H,就得到国标码。如:字的国标码为3123H,它是经过下面的转换得到 的:1703D>1103H->+20H>3123H

国标码是汉字信息交换的标准编码,但因其前后字节的最高位为0,与ASCII码发生冲突,如 字,国标码为31H23H,而西文字符“1” “#”SCII也为31H23H,现假如内存中有两个字节为31H23H, 这到底是一个汉字,还是两个西文字符“1”;“#”? 于是就出现了 二义性,显然,国标码是不可能在计算机内部直接采用的,于是,;汉字的机内码采用变形国标码,其变换方法为:将国标码的每个字节都加上128,即将两个字 节的最高位由01,其余7位不变,如:由上面我们知道,字的国标码为3123H,前字节为00110001B,后字节为00100011B,高位 110110001B10100011B 即为B1A3H,因此, 保字的机内码就是B1A3H;

汉字信息处理过程众所周知,计算机并不能识别汉字,因此必须要把每个字符转换成计算机能唯一识别的由01组成的代码,这个代码称为机内码

汉字机内码的每个字节都大于128,这就解决了与西文字符的ASCII码冲突的问题。

5. 测试

FILE *fp;

                int i = 12;

                int j = 12;

               

                fp = fopen(”01.txt”,”wb”);

                fprintf(fp,”%d”,i);

                fputc(”,fp);

                fwrite(&j,sizeof(int),1,fp);

               

                fclose(fp);

即使是用二进制打开,但如果你用fputc,fputsfprintf这些函数,其实还是和用文本文件打开一样。只有用到fwrite/fread函数,才会看到一个整型占4个字节。

按二进制写文件指的是直接按照数据在内存中的表现形式写入文件。例如,如果int型数据在内存中用 4 个字节表示,则写这个int数据的时候直接把对应的内存中 4 个字节的内容写入文件。在此过程中数据不需要做任何转换,所以效率较高。

据有字符型和非字符型(数)两种。按文本方式写文件指的是将数据转换为对应的字符型数据之后再写入文件。对于字符型数据,由于其本身就是ASCII码字 符,一般不必转换,直接写入文件。但是,由于不同的系统对于换行符()有不同的处理(转换)方式,在有的系统(如Windows)下也会对 ‘ n’ 作适当的转换。

对于非字符型数据,都要进行转换处理。例如:int m = 12; 以及 double f = 2.3;,分别按照 “%d”“%lf” 方式将 m f 写入文件的时候,写入的分别是 ‘1′‘2′ 两个字符以及 ‘2′‘.’ ‘3′ 等三个字符的ASCII码值。显然,如果按照二进制方式写的话,在文件中一般 m 要占 4 个字节、f 要占 8 个字节

没有评论 »

关于swap,虚拟内存和page的区别

十一月 27, 2008 | linux | RSS 2.0

以前的操作系统是实模式,例如dos。每个时候只有一个进程在跑,这个进程使用全部的物理内存。

后来发展到保护模式,分时多进程。一个CPU上跑多个进程, 但进程不知道到底有多少内存可以用,它能访问内存最大地址。例如16位系统就能访问2^16byte,32位就是2^32位。但是实际上没有那么多内存阿?怎么办?保护模式就应运而生了。

假设进程是一个刘祥,裁判(系统)一发令他就开始跑步。但是裁判说给你1秒,可以跑100米。于是刘祥开始跑步(内存地址),一秒后刘祥只跑了10米,裁判吹哨说:刘祥你先歇会,我要去给王军霞吹哨呢,现记住你跑到哪里了(保护),等会从这里开始。裁判给王军霞吹哨,一只跑一秒,回来再给刘祥吹哨再跑1秒,如此往复。开始跑步的人少,刘祥还可以站在跑道上休息。后来跑步的人越来越多,跑道都挤满了人,那么只能把一些人移动到跑道旁的草地上休息(交换)。后来发现有些人横七竖八的躺着,占了不少空间,于是规定每个人只能站着(page),这样可以容纳很多的人。

swap — 草地,就是存放page的硬盘空间。
virtual memory — 假设刘祥跑n圈就已经是到北京的距离了,可是他们还在原地。虚拟就是不存在的。
page — 草地上的格,每次只容纳一个人。

为了提高磁盘存取效率, Linux做了一些精心的设计, 除了对dentry进行缓存(用于VFS,加速文件路径名到inode的转换),还采取了两种主要Cache方式:Buffer Cache和PageCache.前者针对磁盘块的读写,后者针对文件inode的读写.这些Cache有效缩短了I/O系统调用(比如read,write,getdents)的时间.

内存活动基本上可以用3个数字来量化:活动虚拟内存总量,交换(swapping)率和调页(paging)率.其中第一个数字表明内存的总需求量,后两个数字表示那些内存中有多少比例正处在使用之中.目标是减少内存活动或增加内存量,直到调页率保持在一个可以接受的水平上为止.

活动虚拟内存的总量(VM)=实际内存大小(size of real memory)(物理内存)+使用的交换空间大小(amount of swap space used)

当程序运行需要的内存大于物理内存时,UNIX系统采用了调页机制,即系统copy一些内存中的页面到磁盘上,腾出来空间供进程使用。

大多数系统可以忍受偶尔的调页,但是频繁的调页会使系统性能急剧下降。

UNIX内存管理:UNIX系统通过2种方法进行内存管理,“调页算法”,“交换技术”。

调页算法是将内存中最近不常使用的页面换到磁盘上,把常使用的页面(活动页面)保留在内存中供进程使用。

交换技术是系统将整个进程,而不是部分页面,全部换到磁盘上。正常情况下,系统会发生一些交换过程。

当内存严重不足时,系统会频繁使用调页和交换,这增加了磁盘I/O的负载。进一步降低了系统对作业的执行速度,即系统I/O资源问题又会影响到内存资源的分配。

Unix的虚拟内存

Unix的虚拟内存是一个十分复杂的子系统,它实现了进程间代码与数据共享机制的透明性,并能够分配比系统现有物理内存更多的内存,某些操作系统的虚存甚至能通过提供缓存功能影响到文件系统的性能,各种风格的UNIX的虚存的实现方式区别很大,但都离不开下面的4个概念。

1:实际内存

实际内存是指一个系统中实际存在的物理内存,称为RAM。实际内存是存储临时数据最快最有效的方式,因此必须尽可能地分配给应用程序,现在的RAM的形式有多种:SIMM、DIMM、Rambus、DDR等,很多RAM都可以使用纠错机制(ECC)。

2:交换空间

交换空间是专门用于临时存储内存的一块磁盘空间,通常在页面调度和交换进程数据时使用,通常推荐交换空间的大小应该是物理内存的二到四倍。

3:页面调度

页面调度是指从磁盘向内存传输数据,以及相反的过程,这个过程之所以被称为页面调度,是因为Unix内存被平均划分成大小相等的页面;通常页面大小为4KB和8KB(在Solaris中可以用pagesize命令查看)。当可执行程序开始运行时,它的映象会一页一页地从磁盘中换入,与此类似,当某些内存在一段时间内空闲,就可以把它们换出到交换空间中,这样就可以把空闲的RAM交给其他需要它的程序使用。

4:交换

页面调度通常容易和交换的概念混淆,页面调度是指把一个进程所占内存的空闲部分传输到磁盘上,而交换是指当系统中实际的内存已不够满足新的分配需求时,把整个进程传输到磁盘上,交换活动通常意味着内存不足。

vmstat监视内存性能:该命令用来检查虚拟内存的统计信息,并可显示有关进程状态、空闲和交换空间、调页、磁盘空间、CPU负载和交换,cache刷新以及中断等方面的信息。

Procs

r: The number of processes waiting for run time.

运行的和等待(CPU时间片)运行的进程数,这个值也可以判断是否需要增加CPU(长期大于1)

b: The number of processes in uninterruptable sleep.

处于不可中断状态的进程数,常见的情况是由IO引起的

w: The number of processes swapped out but otherwise runnable.

Memory

swpd: the amount of virtual memory used (kB).

free: the amount of idle memory (kB).

空闲的物理内存

buff: the amount of memory used as buffers (kB).

作为buffer cache的内存,对块设备的读写进行缓冲

cache: the amount of memory used as cache.

Swap

si: Amount of memory swapped in from disk (kB/s). 虚拟内存的页导入(从SWAP DISK导入RAM)

so: Amount of memory swapped to disk (kB/s). 虚拟内存的页导出.

(从RAM到SWAP DISK)

没有评论 »

为什么我的眼里会含泪水

十一月 25, 2008 | 心情杂记 | RSS 2.0

近段时间每每听二泉映月,心情都完全沉静了下来,不仅仅震撼,远离了了世事得喧嚣。
也许是在一个xxx得社会里想找到这样一片净土真难,每天奔波于工作中,身心得疲惫找不到医治的良药。只有沉静在这样得音乐中才得到安慰,沿着曲里得旋律去寻找一片历史的天空。
真的,二泉映月真是纤纤抽动我心。感叹阿炳旷世之才,也为自己能听到这样美妙得音乐而欣慰,终于知道艺术得魅力了。终于理解了冯友兰哲学上境界中的第三境界。日本音乐家小泽征尔说要跪着听找个曲子,看来我快要达到找个境界了。曾经听一首学友的曲子李香兰。让我流下了宝贵得泪水。
想起让我流泪的曲子,和电影发现基本上都是凄惨得。悲怆得作品。妈妈再爱我一次,梁祝,李香兰,二泉映月。
也许是这些作品让我看到了真爱,看到悲苦,让我更加懂得珍惜现在的生活。
人,活着无论物质生活多么缺乏,一定让自己的精神丰富起来。可以相信一个只有物质生活,只注重物质生活的是多么得悲哀,因为他看不到精神的伟大。体会不到人生的全部意义。人,不只是为了生活的动物。让我的眼里尽管是泪水。那说说明我又一次触摸到了艺术的真谛。

没有评论 »

fck捕获事件支持ff,ie

十一月 21, 2008 | js/web | RSS 2.0

function FCKeditor_OnComplete( editorInstance )
{
 if (document.all) {      
    // IE
        editorInstance.EditorDocument.attachEvent(”onkeyup”, editor_keyup) ;
    } else {
       // other browser
       editorInstance.EditorDocument.addEventListener( ‘keyup’, editor_keyup, true ) ;
    }   
}

没有评论 »