数据库进阶5 Mysql 性能优化20个原则(3)

12. Prepared Statements

Prepared Statements很像存储过程,是一种运行在后台的SQL语句集合,我们可以从使用 prepared statements 获得很多好处,无论是性能问题还是安全问题。

Prepared Statements 可以检查一些你绑定好的变量,这样可以保护你的程序不会受到“SQL注入式”攻击。当然,你也可以手动地检查你的这些变量,然而,手动的检查容易出问题,而且很经常会被程序员忘了。当我们使用一些framework或是ORM的时候,这样的问题会好一些。

在性能方面,当一个相同的查询被使用多次的时候,这会为你带来可观的性能优势。你可以给这些Prepared Statements定义一些参数,而MySQL只会解析一次。

虽然最新版本的MySQL在传输Prepared Statements是使用二进制形势,所以这会使得网络传输非常有效率。

当然,也有一些情况下,我们需要避免使用Prepared Statements,因为其不支持查询缓存。但据说版本5.1后支持了。

在PHP中要使用prepared statements,你可以查看其使用手册:mysqli 扩展 或是使用数据库抽象层,如:PDO.

 1// 创建 prepared statement
 2if ($stmt = $mysqli->prepare("SELECT username FROM user WHERE state=?")) {
 3
 4    // 绑定参数
 5    $stmt->bind_param("s",$state);
 6
 7    // 执行
 8    $stmt->execute();
 9
10    // 绑定结果
11    $stmt->bind_result($username);
12
13    // 移动游标
14    $stmt->fetch();
15
16    printf("%s is from %s\n",$username,$state);
17
18    $stmt->close();
19}

正常的情况下,当你在当你在你的脚本中执行一个SQL语句的时候,你的程序会停在那里直到没这个SQL语句返回,然后你的程序再往下继续执行。你可以使用无缓冲查询来改变这个行为。

13. 无缓冲的查询

关于这个事情,在PHP的文档中有一个非常不错的说明: mysql_unbuffered_query() 函数:

“mysql_unbuffered_query() sends the SQL query query to MySQL without automatically fetching and buffering the result rows as mysql_query() does. This saves a considerable amount of memory with SQL queries that produce large result sets, and you can start working on the result set immediately after the first row has been retrieved as you don’t have to wait until the complete SQL query has been performed.”

上面那句话翻译过来是说,mysql_unbuffered_query() 发送一个SQL语句到MySQL而并不像mysql_query()一样去自动fethch和缓存结果。这会相当节约很多可观的内存,尤其是那些会产生大量结果的查询语句,并且,你不需要等到所有的结果都返回,只需要第一行数据返回的时候,你就可以开始马上开始工作于查询结果了。

然而,这会有一些限制。因为你要么把所有行都读走,或是你要在进行下一次的查询前调用 mysql_free_result() 清除结果。而且, mysql_num_rows() 或 mysql_data_seek() 将无法使用。所以,是否使用无缓冲的查询你需要仔细考虑。

14. 把IP地址存成 UNSIGNED INT

很多程序员都会创建一个 VARCHAR(15) 字段来存放字符串形式的IP而不是整形的IP。如果你用整形来存放,只需要4个字节,并且你可以有定长的字段。而且,这会为你带来查询上的优势,尤其是当你需要使用这样的WHERE条件:IP between ip1 and ip2。

我们必需要使用UNSIGNED INT,因为 IP地址会使用整个32位的无符号整形。

而你的查询,你可以使用 INET_ATON() 来把一个字符串IP转成一个整形,并使用 INET_NTOA() 把一个整形转成一个字符串IP。在PHP中,也有这样的函数 ip2long() 和 long2ip()。

1$r = "UPDATE users SET ip = INET_ATON('{$_SERVER['REMOTE_ADDR']}') WHERE user_id = $user_id";

如果表中的所有字段都是“固定长度”的,整个表会被认为是 “static” 或 “fixed-length”。 例如,表中没有如下类型的字段: VARCHAR,TEXT,BLOB。只要你包括了其中一个这些字段,那么这个表就不是“固定长度静态表”了,这样,MySQL 引擎会用另一种方法来处理。

15. 固定长度的表会更快

固定长度的表会提高性能,因为MySQL搜寻得会更快一些,因为这些固定的长度是很容易计算下一个数据的偏移量的,所以读取的自然也会很快。而如果字段不是定长的,那么,每一次要找下一条的话,需要程序找到主键。

并且,固定长度的表也更容易被缓存和重建。不过,唯一的副作用是,固定长度的字段会浪费一些空间,因为定长的字段无论你用不用,他都是要分配那么多的空间。

使用“垂直分割”技术(见下一条),你可以分割你的表成为两个一个是定长的,一个则是不定长的。

本文分享自微信公众号 - 高性能服务器开发(easyserverdev)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-07-20

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏PHP在线

MySQL SQL语句优化的10条建议

1、将经常要用到的字段(比如经常要用这些字段来排序,或者用来做搜索),则最好将这些字段设为索引 2、字段的种类尽可能用int或者tinyint类型。另外字段尽可...

34750
来自专栏Java3y

移动商城第五篇(用户模块)【用户登陆、回显用户、拦截器、收货地址】

移动商城【用户登陆、回显用户】 我们来实现用户登陆的功能: ? 当点击的时候,出来的是一个弹出框,我们想要切换成一个页面。 ? 找到对应的事件、切换成我们的页面...

65770
来自专栏Golang语言社区

服务器 数据库设计技巧--2

8.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如: select id from t wheresubstring...

36090
来自专栏互联网开发者交流社区

数据库的总结

16940
来自专栏Django Scrapy

倒排索引

主楼搜索引擎的主流算法 倒排索引源于实际应用中需要根据属性的值来记录,这种只能怪索引表中的每一项都包括一个属性值和具有该属性值的各记录的地址。由于不是由记录开...

49860
来自专栏杨建荣的学习笔记

有趣的rownum测试(r10笔记第49天)

rownum在平时的使用中总是一个很自然的语法。如果说这个rownum是否有规律,可能很多人都会模棱两可。到底是还是不是呢,我们来做几个测试来说明。 这个结果也...

355120
来自专栏电光石火

mybatis获取update的id

平常我门都是更新数据,用更新的条件再查询一次,得到更新的记录。这样我门就进行了两次数据库操作,链接了两次数据库。增加了接口的处理事件,因为链接数据库是很耗时...

39260
来自专栏Jackson0714

【Discuz】-QQ互联登陆提示错误信息:Unknown column 'conuintoken' in 'field list'

371110
来自专栏FreeBuf

移位溢注:告别靠人品的偏移注入

在Access数据库类型注入的时候,我们获取不到列名(前提是有表名),一般会选择使用偏移注入,但是这种注入方式往往借助的是个人的人品,且步骤繁琐。本文中我们研究...

25360
来自专栏软件开发

一个小时学会MySQL数据库

随着移动互联网的结束与人工智能的到来大数据变成越来越重要,下一个成功者应该是拥有海量数据的,数据与数据库你应该知道。

36230

扫码关注云+社区

领取腾讯云代金券