代码细节

some code staff

  • 自从有了微薄后博客就写得少了,上一篇博客已经是6月份写的了… 从写第一篇关于MySQL源码的文章之后也已经过了很久,继续上路。

    优化器是关系数据库的一个重要而有特色的部分,优化器的理论和实践也多半也都很复杂,本系列文章希望通过解析MySQL优化器,来用好MySQL,扬其长,避其短。顺便也一窥关系数据库优化器的实现思路。文章将重点介绍重要的数据结构和数据结构之间的关系,而不是侧重于代码(”Bad programmers worry about the code. Good programmers worry about data structures and their relationships.”)。

    0 写在前面

    本文解决了什么问题:希望通过这些文章能够帮你更加顺畅的理解MySQL优化器的行为;在你阅读MySQL源代码之前了解更多的背后思路。

    本文不解决什么问题:教你如何读懂源代码;

    这个系列很长,大概按这样的思路进行下去: 基本的数据结构、语法解析、JOIN的主要算法、JOIN顺序和单表访问。数据结构(以及他们的关系)和算法流程总是相互穿插介绍。

    建议阅读:参考文献中的文章和书籍,都建议在阅读本文之前阅读。

    1 SQL语句解析基础

    1.1 语法解析基础/Flex与Bison

    MySQL语法解析封装在函数MYSQLparser中完成。跟其他的语法解析器一样,它包含两个模块:词法分析(Lexical scanner)和语法规则(Grammar rule module)。词法分析将整个SQL语句打碎成一个个单词(Token),而语法规则模块则根据MySQL定义的语法规则生成对应的数据结构,并存储在对象THD->LEX结构当中。最后优化器,根据这里的数据,生成执行计划,再调用存储引擎接口执行。

    词法分析和语法规则模块有两个较成熟的开源工具Flex和Bison分别用来解决这两个问题。MySQL出于性能和灵活考虑,选择了自己完成词法解析部分,语法规则部分使用Bison。词法解析和Bison沟通的核心函数是由词法解析器提供的函数接口yylex(),在Bison中,必要的时候调用yylex()获得词法解析的数据,完成自己的语法解析。Bison的入口时yyparse(),在MySQL中是,MYSQLParse。

    如果对词法分析和语法规则模块感到陌生,建议阅读参考文献[4][5][6]先注1,否则很难理解整个架构,或者至少会有很强的断层感。而且,根据Bison的Action追踪MySQL数据的存储结构是很有效的。 (more…)

  • 如何编译安装一个php模块

    ·

    不止一次需要这么做了。

    如果你需要的扩展在yum/apt仓库中没有的话,那需要自己编译了。

    1. 下载PHP5.2.9的源代码(根据你php的版本选择)
    2. 编译模块

    进入对应模块的源码目录,然后:phpize、configure、make

    $tar zxvf tar zxvf php-5.2.9.tar.gz $cd php-5.2.9/ext/curl $phpize Configuring for: PHP Api Version: 20041225 Zend Module Api No: 20060613 Zend Extension Api No: 220060519 $./configure --with-php-config=/opt/php/bin/php-config checking for egrep... grep -E checking for a sed that does not truncate output... /bin/sed ...... configure: creating ./config.status config.status: creating config.h $make ...... Build complete. Don't forget to run 'make test'.
    3.将扩展文件(.so)cp到php的扩展目录

    扩展目录的位置可以通过phpinfo的输出结果看到,也可以在php.ini文件中看到。

    例如:

    cp modules/sockets.so /home/admin/php/ext/

    然后编辑php.ini文件

    ; extension_dir directive above.
    extension_dir = “/home/admin/php/ext/”
    extension=memcache.so
    extension=curl.so
    extension=rrdtool.so
    extension=oci8.so
    extension=sockets.so
    4. 重启你的apache,Job done

    可以通过phpinfo()来的输出来查看是否成功安装对应的模块。

    参考:Compiling shared PECL extensions with phpize

  • 这又是一篇介绍Semi-sync的文章。

    Semi-sync主库在一定时间内(可配置的超时时间),如果没有收到备库的响应,则会超时从而降级为普通的replication复制。如果超时发生,有时需要查清什么原因导致备库没有及时响应,一方面可以从备库的日志着手,另一方面,如果需要更细致的信息则需要从备库端的网络包查找原因。这里介绍如何分析一个Semi-sync备库响应主库的数据包。

    概述:先使用tcpdump抓取正确(主要是src和dst都正确)的数据包;然后借助wireshark玻璃TCP/IP等层的头信息,仅保留发送的MySQL数据包;再分析MySQL Semi-sync Slave响应的协议。

    1. tcpdump原始数据包

    通过如下tcpdump抓取主机的网络包:

    nohup tcpdump -n -nn -tttt -i bond0 -s 65535 'port 3306 and ((dst host master.host and src host slave.host and len < 100) or (dst host slave.host and src host master.host))' -w tcpdump.ret -C 50 &

    参数简单说明:

    -n 表示ip不要转换为主机名 -nn表示端口号,不要转为为服务名(例如3306会被转换为mysql) -tttt 打印出完成的格式化的时间戳 -C 50 表示抓取的结果放到文件中,文件大小不超过50MB
    2. 使用wireshark找到对应的包

    (more…)

  • 格式化输出SQL

    ·

    工作中,经常需要在web页面中把SQL(MySQL)展示给开发人员,如果SQL不格式话,例如:

    sqlsample_1

    上面的SQL,咋一眼,很难看出SQL的目的是什么。而格式化的输出可以让SQL更易读懂,如:

    screenshot-sqlparser

    上周末做了一个简单的PHP SQL Format工具,可以实现上述功能,这里简单的介绍如何使用PHP SQL Format(也可以参考这里)。

    1. 下载相关文件并解压到你的WEB目录

    有如下文件:

    将这些文件都放入web目录下的sqlparserlib目录下。

    2. 编写如下PHP/HTML代码
    <link rel="stylesheet" type="text/css" href="sqlparserlib/sqlsyntax.css" /> <?php define('PARSER_LIB_ROOT', "/opt/www/sqlparserlib/"); require_once PARSER_LIB_ROOT.'sqlparser.lib.php'; function SQLFormatPHP($sql){ return PMA_SQP_formatHtml(PMA_SQP_parse($sql)); } $sql = "SELECT FROM (select from dual)"; echo SQLFormatPHP($sql); ?>

    只要把上面php代码中的$sql改成你的输入SQL就OK了。

    3. 需要注意的问题

    * 上面的代码中,路径一定要注意,在你的代码中也必须引用正确的路径

    * 上面的sqlsyntax.css定义了很多CSS,注意不要与你的CSS冲突了

    * 上面require_once很多函数,注意不要与你的函数冲突了

    4. 实现说明

    这里使用的代码包sqlparser.lib.php来自phpMyAdmin,稍微做了一些改动,让这块代码能够独立使用。

    看了Stackoverflow上很多朋友也有类似问题,所以就花了几个小时的尝试,把phpMyAdmin里面SQL Parser相关的代码独立出来,lib中有很多的代码都应该是无用的,我并没有做精简,所以你最求效率的话,可能需要自己再优化一下。

  • 一个有趣的perl函数

    ·

    入职已经489天了,新鲜事很多,不过更多应该是无趣、枯燥的日常:装很多的数据库、反复的测试、写很多的脚本…… 不过,在这繁忙工作中,还是希望自己能够保持一份趣味。

    下面这个perl函数就是帮你保持脚本有趣的一个办法。

    在你的Perl脚本中下面的函数,并在脚本的第一行调用之。函数会在你的输出前随机的输出一条“名言”,让你在枯燥的调试程序时,仍然保持一份清醒:

    use MIME::Base64; ####################################################### # This is a interesting function by orczhou@gmail.com # It outputs a random quote ####################################################### sub randomQuote{ my @quote; push(@quote,"S2VlcCBpdCBzaW1wbGUsIFN0dXBpZA=="); push(@quote,"VG9tb3Jyb3cgaXMgYW5vdGhlciBkYXk="); push(@quote,"TGlmZSBpcyBsaWtlIGEgYm94IG9mY2hvY29sYXRlcw=="); push(@quote,"VGhlIGFuZ3J5IGlzIHRoYXQgdGFraW5nIHRoZSBvdGhlcidzIG1pc3Rha2UgdG8gcHVuaXNoIG9uZXNlbGY="); push(@quote,"VGhlIGhvcGUgb2YgdG9tb3Jyb3cgbGV0cyB1cyBmb3JnZXQgdG9kYXkncyBwYWlu"); push(@quote,"VGhlIHBsYWNlIHdoaWNoIHRoZSBpZGVhbCBpcyBpbiwgdGhlIGhlbGwgbWF5YmUgYSBoZWF2ZW4="); push(@quote,"Rm9yIGhpcyBsb25nIGFuZCBub24tdmlvbGVudCBzdHJ1Z2dsZSBmb3IgZnVuZGFtZW50YWwgaHVtYW4gcmlnaHRzIGluIENoaW5h"); push(@quote,"V2hhdCBpcyBkb25lIGJ5IG5pZ2h0IGFwcGVhcnMgYnkgZGF5"); push(@quote,"SWYgeW91IHdhbnQgdG8gaGF2ZSB0aGUgcGVyZmVjdCBmcmllbmRzaGlwLCBwb3NzaWJseSB5b3UgbWF5IGZpbmQgbm8gZnJpZW5kIGZvciBhbGw gbGlmZXRpbWU="); push(@quote,"VGhlIGV4cGVyaWVuY2UgdGFrZXMgb3V0IGJ5IHRoZSBlc3NlbmNlIG9mIHBhaW4="); push(@quote,"VGhlIGJpZ2dlc3QgbWlzdGFrZSBpbiBsaWZlIGlzIHRoZSB1bmNlYXNpbmdseSB3b3JyaWVkIGFib3V0IG1ha2luZyBtaXN0YWtl"); push(@quote,"TGF6aW5lc3Mgd2lsbCBjYXVzZSB5b3UgcGFpbg=="); push(@quote,"S2VlcCB0aGUgcGFzc2lvbiBmb3IgeW91ciBqb2I="); push(@quote,"VGhlcmUgaXMgb2Z0ZW4gbGVzcyBkYW5nZXIgaW4gdGhlIHRoaW5ncyB3ZSBmZWFyIHRoYW4gaW4gdGhlIHRoaW5ncyB3ZSBkZXNpcmU="); push(@quote,"WW91IGNhbiB1c2Ugc2NyaXB0IGRvIG1vcmUgd29yayxidXQgc2FkZGx5IGl0IG1ha2UgbW9yZSBqb2JzIGNvbWUgdG8gdQ=="); push(@quote,"TXkgbmFtZSBpcyBteXNxbGRhdXRvLkkgd2FzIGNyZWF0ZWQgYnkgb3JjemhvdQ=="); #push(@quote,""); my $count = scalar(@quote); my $rand_num = int(rand($count)); print decode_base64($quote[$rand_num])."\n"; } randomQuote();

    如果觉得上面的代码,破坏了脚本的输出,可以使用参数控制其是否输出。

  • 如果遇到如下错误:

    Can’t open file: ‘.\test\mytable.frm’ (errno: 24)
    shell> perror 24
    OS error code 24: Too many open files

    这就是MySQL的文件描述不够用了。先说解决办法,再说背后的原因吧。

    1. 如何解决

    第一步:设置OS参数(如果你有权限的话):

    文件/etc/security/limits.conf新增如下行:

    mysql soft nofile 65535
    mysql hard nofile 65535

    上面的配置,是OS限制各个用户能够打开的文件描述符限制(hard soft区别参看man ulimit),新增上面两行,表示mysql用户能够打开65535个文件描述符(可以使用lsof -u mysql|wc -l查看当前打开了多少个文件描述符)。

    第二步:修改MySQL参数:
    在MySQL配置文件my.cnf中新增下面的行

    open_files_limit = 65535
    innodb_open_files=65535

    然后重启你的MySQL一般问题就解决了。

    2. 背后的问题

    (more…)