摘自Discuz官网:http://dev.discuz.org/wiki/index.php?title=%E7%BC%96%E7%A0%81%E8%A7%84%E8%8C%83#.E6.80.A7.E8.83.BD.E4.B8.8E.E6.95.88.E7.8E.87

字段结构

  • 允许NULL值的字段,数据库在进行比较操作时,会先判断其是否为NULL,非NULL时才进行值的必对。因此基于效率的考虑,所有字段均不能为空,即全部NOT NULL;
  • 预计不会存储非负数的字段,例如各项id、发帖数等,必须设置为UNSIGNED类型。UNSIGNED类型比非UNSIGNED类型所能存储的正整数范围大一倍,因此能获得更大的数值存储空间;
  • 存储开关、选项数据的字段,通常使用tinyint(1)非UNSIGNED类型,少数情况也可能使用enum()结果集的方式。tinyint作为开关字段时,通常1为打开;0为关闭;-1为特殊数据,例如N/A(不可用);高于1的为特殊结果或开关二进制数组合(详见Discuz!中相关代码);
  • MEMORY/HEAP类型的表中,要尤其注意规划节约使用存储空间,这将节约更多内存。例如cdb_sessions表中,就将IP地址的存储拆分为4个tinyint(3) UNSIGNED类型的字段,而没有采用char(15)的方式;
  • 任何类型的数据表,字段空间应当本着足够用,不浪费的原则,数值类型的字段取值范围见下表:
字段类型 存储空间(b) UNSIGNED 取值范围
tinyint 1 -128~127
0~255
smallint 2 -32768~32767
0~65535
mediumint 3 -8388608~8388607
0~16777215
int 4 -2147483648~2147483647
0~4294967295
bigint 8 -9223372036854775808~9223372036854775807
0~18446744073709551615

SQL语句

  • 所有SQL语句中,除了表名、字段名称以外,全部语句和函数均需大写,应当杜绝小写方式或大小写混杂的写法。例如select * from cdb_members;是不符合规范的写法。
  • 很长的SQL语句应当有适当的断行,依据JOIN、FROM、ORDER BY等关键字进行界定。
  • 通常情况下,在对多表进行操作时,要根据不同表名称,对每个表指定一个1~2个字母的缩写,以利于语句简洁和可读性。
如下的语句范例,是符合规范的:
$query = $db->query("SELECT s.*, m.* FROM {$tablepre}sessions s, {$tablepre}members m WHERE m.uid=s.uid AND s.sid='$sid');

定长与变长表

包含任何varchar、text等变长字段的数据表,即为变长表,反之则为定长表。

  • 对于变长表,由于记录大小不同,在其上进行许多删除和更改将会使表中的碎片更多。需要定期运行OPTIMIZE TABLE以保持性能。而定长表就没有这个问题;
  • 如果表中有可变长的字段,将它们转换为定长字段能够改进性能,因为定长记录易于处理。但在试图这样做之前,应该考虑下列问题:
  • 使用定长列涉及某种折衷。它们更快,但占用的空间更多。char(n) 类型列的每个值总要占用n 个字节(即使空串也是如此),因为在表中存储时,值的长度不够将在右边补空格;
  • 而varchar(n)类型的列所占空间较少,因为只给它们分配存储每个值所需要的空间,每个值再加一个字节用于记录其长度。因此,如果在char和varchar类型之间进行选择,需要对时间与空间作出折衷;
  • 变长表到定长表的转换,不能只转换一个可变长字段,必须对它们全部进行转换。而且必须使用一个ALTER TABLE语句同时全部转换,否则转换将不起作用;
  • 有时不能使用定长类型,即使想这样做也不行。例如对于比255字符更长的串,没有定长类型;
  • 在设计表结构时如果能够使用定长数据类型尽量用定长的,因为定长表的查询、检索、更新速度都很快。必要时可以把部分关键的、承担频繁访问的表拆分,例如定长数据一个表,非定长数据一个表。例如Discuz!的cdb_members和cdb_memberfields表、cdb_forums和cdb_forumfields表等。因此规划数据结构时需要进行全局考虑;

进行表结构设计时,应当做到恰到好处,反复推敲,从而实现最优的数据存储体系。

运算与检索

  • 数值运算一般比字符串运算更快。例如比较运算,可在单一运算中对数进行比较。而串运算涉及几个逐字节的比较,如果串更长的话,这种比较还要多。
  • 如果串列的值数目有限,应该利用普通整型或emum类型来获得数值运算的优越性。
  • 更小的字段类型永远比更大的字段类型处理要快得多。对于字符串,其处理时间与串长度直接相关。一般情况下,较小的表处理更快。对于定长表,应该选择最小的类型,只要能存储所需范围的值即可。例如,如果mediumint够用,就不要选择bigint。对于可变长类型,也仍然能够节省空间。一个TEXT 类型的值用2 字节记录值的长度,而一个LONGTEXT 则用4字节记录其值的长度。如果存储的值长度永远不会超过64KB,使用TEXT 将使每个值节省2字节。

结构优化与索引优化

索引能加快查询速度,而索引优化和查询优化是相辅相成的,既可以依据查询对索引进行优化,也可以依据现有索引对查询进行优化,这取决于修改查询或索引,哪个对现有产品架构和效率的影响最小。
索引优化与查询优化是多年经验积累的结晶,在此无法详述,但仍然给出几条最基本的准则。
首先,根据产品的实际运行和被访问情况,找出哪些SQL语句是最常被执行的。最常被执行和最常出现在程序中是完全不同的概念。最常被执行的SQL语句,又可被划分为对大表(数据条目多的)和对小表(数据条目少的)的操作。无论大表或小表,有可分为读(SELECT)多、写(UPDATE/INSERT)多或读写都多的操作。
对常被执行的SQL语句而言,对大表操作需要尤其注意:

  • 写操作多的,通常可使用写入缓存的方法,先将需要写或需要更新的数据缓存至文件或其他表,定期对大表进行批量写操作,例如Discuz!中点击数延迟更新机制,就是依据此原理实现。同时,应尽量使得常被读写的大表为定长类型,即便原本的结构中大表并非定长。大表定长化,可以通过改变数据存储结构和数据读取方式,将一个大表拆成一个读写多的定长表,和一个读多写少的变长表来实现;
  • 读操作多的,需要依据SQL查询频率设置专门针对高频SQL语句的索引和联合索引。
而小表就相对简单,加入符合查询要求的特定索引,通常效果比较明显。同时,定长化小表也有益于效率和负载能力的提高。字段比较少的小定长表,甚至可以不需要索引。
其次,看SQL语句的条件和排序字段是否动态性很高(即根据不同功能开关或属性,SQL查询条件和排序字段的变化很大的情况),动态性过高的SQL语句是无法通过索引进行优化的。惟一的办法只有将数据缓存起来,定期更新,适用于结果对实效性要求不高的场合。

MySQL索引,常用的有PRIMARY KEY、INDEX、UNIQUE几种,详情请查阅MySQL文档。通常,在单表数据值不重复的情况下,PRIMARY KEY和UNIQUE索引比INDEX更快,请酌情使用。
事实上,索引是将条件查询、排序的读操作资源消耗,分布到了写操作中,索引越多,耗费磁盘空间越大,写操作越慢。因此,索引决不能盲目添加。对字段索引与否,最根本的出发点,依次仍然是SQL语句执行的概率、表的大小和写操作的频繁程度。

查询优化

MySQL中并没有提供针对查询条件的优化功能,因此需要开发者在程序中对查询条件的先后顺序人工进行优化。例如如下的SQL语句:
SELECT * FROM table WHERE a>’0’ AND b<’1’ ORDER BY c LIMIT 10;
事实上无论a>’0’还是b<’1’哪个条件在前,得到的结果都是一样的,但查询速度就大不相同,尤其在对大表进行操作时。
开发者需要牢记这个原则:最先出现的条件,一定是过滤和排除掉更多结果的条件;第二出现的次之;以此类推。因而,表中不同字段的值的分布,对查询速度有着很大影响。而ORDER BY中的条件,只与索引有关,与条件顺序无关。
除了条件顺序优化以外,针对固定或相对固定的SQL查询语句,还可以通过对索引结构进行优化,进而实现相当高的查询速度。原则是:在大多数情况下,根据WHERE条件的先后顺序和ORDER BY的排序字段的先后顺序而建立的联合索引,就是与这条SQL语句匹配的最优索引结构。尽管,事实的产品中不能只考虑一条SQL语句,也不能不考虑空间占用而建立太多的索引。
同样以上面的SQL语句为例,最优的当table表的记录达到百万甚至千万级后,可以明显的看到索引优化带来的速度提升。
依据上面条件优化和索引优化的两个原则,当table表的值为如下方案时,可以得出最优的条件顺序方案:
字段a 字段b 字段c
1 7 11
2 8 10
3 9 13
最优条件:b<’1’ AND a>’0’

最优索引:INDEX abc (b, a, c) 原因:b<’1’作为第一条件可以先过滤掉75%的结果。如果以a>’0’作为第一条件,则只能先过滤掉25%的结果
注意:

  • 字段c由于未出现于条件中,故条件顺序优化与其无关
  • 最优索引由最优条件顺序得来,而非由例子中的SQL语句得来
  • 索引并非修改数据存储的物理顺序,而是通过对应特定偏移量的物理数据而实现的虚拟指针
EXPLAIN语句是检测索引和查询能否良好匹配的简便方法。在phpMyAdmin或其他MySQL客户端中运行EXPLAIN+查询语句,例如EXPLAIN SELECT * FROM table WHERE a>’0’ AND b<’1’ ORDER BY c;这种形式,即使得开发者无需模拟上百万条数据,也可以验证索引是否合理,相关细节请参考MySQL说明。
值得提出的是,Using filesort是最不应当出现的情况,如果EXPLAIN得出此结果,说明数据库为这个查询专门建立了一个用以缓存结果的临时表文件,并在查询结束后删除。众所周知,硬盘I/O速度始终是计算机存储的瓶颈,因此,查询中应当尽全力避免高执行频率的SQL语句使用filesort。尽管,开发者永远都不可能保证产品中的全部SQL语句都不会使用filesort。
限于篇幅,本文档远远没有涵盖数据库优化的方方面面,例如:联合索引与普通索引的可重用性、JOIN连接的索引设计、MEMORY/HEAP表等。数据库优化实际上就是在很多因素和利弊间不断权衡、修改,惟有在成功与失败经验中反复推敲才能得出的经验,这种经验往往就是最难能可贵和价值连城的。

兼容性问题

  • 由于MySQL 3.23至5.0的变化很大,因此程序中尽量不使用特殊的SQL语句,以免带来兼容性问题,并给数据库移植造成困难。
  • 通常在MySQL 4.1以上版本,Discuz!应使用相当的字符集来存储,例如GBK/BIG5/UTF-8。传统的latin1编码虽然有一定的兼容性,但仍然不是推荐的选择。使用相应非默认字符集时,程序每次运行时需要使用SET NAMES ‘character_set’;来规定连接、传输和结果的字符集。
  • Mysql 5.0以上新增了数种SQL_MODE,默认的SQL_MODE依服务器安装设置不同而不同,因此程序每次运行时需要使用SET SQL_MODE=’’;来规定当前的SQL模式。

数据库设计性能与效率相关推荐

  1. php pdo效率,php使用mysqli和pdo扩展,测试对比mysql数据库的执行效率完整示例

    本文实例讲述了php使用mysqli和pdo扩展,测试对比mysql数据库的执行效率.分享给大家供大家参考,具体如下: /** * 测试pdo和mysqli的执行效率 */ header(" ...

  2. mysql bulk update_Django bulk_create()、update()与数据库事务的效率对比分析

    下面以创建10000个对象为例进行测试: # 用for循环挨个创建,共花费37秒 for i in range(10000): name="String number %s"%i ...

  3. 什么数据库比mysql效率高_牛x!一款比传统数据库快 100-1000 倍的数据库,来认识一下?...

    一.ClickHouse 是什么? 二.业务问题 三.ClickHouse实践 四.遇到的坑 五.总结 一.ClickHouse 是什么?ClickHouse:是一个用于联机分析(OLAP)的列式数据 ...

  4. 磁盘文件读写和数据库读写哪个效率更高

    假定在程序效率和关键过程相当且不计入缓存等措施的条件下,读写任何类型的数据都没有直接操作文件来的快,不论MSYQL过程如何,最后都要到磁盘上去读这个"文件"(记录存储区等效),所以 ...

  5. 『数据库』数据库系统效率Max--数据库并发控制

    数据库从入门到精通:戳我 文章目录 简介 1. 多用户数据库系统 2.多事务执行方式 2.1 事务串行执行 2.2 交叉并发方式(Interleaved Concurrency) 2.3同时并发方式( ...

  6. mysql数据库更新语句效率_MySQL数据库优化

    一.常用查询 1.1 查询链接MySQL服务器的次数 mysql> show status like 'connections'; +---------------+-------+ | Var ...

  7. 如何提高数据库的访问效率?

    [转载] 1.没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷) 2.I/O吞吐量小,形成了瓶颈效应. 3.没有创建计算列导致查询不优化. 4.内存不足 5.网络速度慢 6.查询出的 ...

  8. 测试数据库sql声明效率

            书写sql当被发现的声明.对于所期望的结果通常是更好地执行. 当面对这些实现的时候如何选择它的最好的,相对来说?这导致了这个博客的话题,如何测试sql效率 以下介绍几种sql语句測试效 ...

  9. Android --- SharePreference 存储与数据库存储的效率分析

    原文链接:https://blog.csdn.net/MacaoPark/article/details/114680449 前言 最近到了一家公司,跟一个同事做项目,比如常规的一些操作用Shared ...

最新文章

  1. [评测] 联想 Mirage Solo 一体机:基本性能强大,价格定位很迷
  2. Little Sub and Triangles
  3. Boost库之function的使用
  4. 数据:以太坊2.0合约质押新增4.15万ETH
  5. Push or pull?
  6. 解析6种常用View 的滑动方法
  7. Javascript:拦截所有AJAX调用,重点处理服务器异常
  8. Eclipse 编辑代码字体的设置
  9. C++入门(4)讲几道例题
  10. 全球运输工业的升级会带来什么
  11. 寒假线上兼职:300-500元/小时,安利一个大学生也能月入8K的线上兼职!
  12. 「镁客·请讲」七鑫易维黄通兵:追求更自然的人机交互,眼球追踪技术正在路上...
  13. 修改系统默认的音频设备
  14. matlab示波器横轴变纵轴,excel表格横轴数据变纵轴-在EXCEL中做图表,横坐标和纵坐标如何调换?...
  15. OSPF基础-个人理解
  16. 由于应用程序的配置不正确,应用程序未能启动,重新安装应用程序可能会纠正这个问题
  17. 1. 大型网站架构演化
  18. 【硬盘测速】一条命令解决硬盘测速问题
  19. 933计算机大纲,2020年华南理工大学933化学综合考研大纲
  20. Unity3D中使用Joystick Pack实现摇杆控制

热门文章

  1. 链表list(链式存储结构实现)_5 线性表的链式存储结构
  2. leetcode前缀树java_LeetCode 实现 Trie (前缀树)
  3. DTD – XML 构建模块概述
  4. springmvc开启事务_java面试题 一 :SpringMvc的流程
  5. java只有整形才能运算符为,java语言基础(二)
  6. HDU1040简单排序题
  7. 有上下界网络流 ---- Zoj3229 Shoot the Bullet|东方文花帖|【模板】有源汇上下界最大流
  8. Mysterious Bacteria LightOJ - 1220[唯一分解定理+思维题]
  9. mysql数据库实验报告jdbc_Jdbc连接数据库实验报告(2)
  10. 一元二次方程实根java_请依次输入一元二次方程的三个系数,并点击计算显示实根...