标签:连载

浏览模式: 标准 | 列表 | 图文
精通MYSQL数据库——连载十七

精通MYSQL数据库——连载十七

主键和外键
数据表之间抽象的关联/引用是依靠具体的主键和外键建立起来的。
主键的任务是帮助MYSQL以最快的速度把一条特定的数据记录在数据表里的位置确定下来,而这种寻址操作在一切需要从多个数据表提取数据的场合都会发生,简单地说,它发生得非常频繁。(例如从数据库里找出ID=12345的数据记录)。包括MYSQL在内的绝大多数数据库系统都允许人们在创建数据表时把多个字段的组合定义为一个主键,但,不管它是由单个字段还是多个字段构成,都必须满足以下条件:
1、主键必须唯一,任意两条数据记录的主键字段绝不允许重复
2、主键应该是紧凑的(为了加快寻址速度,主键都必须有索引,即主索引。主键字段越紧凑,主索引的效率也就越高。主键字段一般都是被另一张数据做外键,外键越紧凑,效率也是会越高)
在大多数数据库上,主键往往都是采用32位或64位的整做来做为主键字段,并让他们自动增长,这已经成为一种标准化的行为,它的好处是程序员无需考虑怎么样才能为每一条新记录找到一个独一无二的主键值的问题了 。

外键的任务是引用另一个数据表的某条记录,只不过这种引用关系是在构造数据库查询命令的时候而不是在声明数据表或者数据列的时候定义的。
外键在数据表的定义声明里毫无特殊之处,在MYSQL看来,外键不过是数据表里的又一个普通字段。在声明一个外键的时候,既不必使用特殊的保留字,也不必为它创建索引。不过,在声明一个外键字段时请注意,不要给这个外键字段加上auto_increment属性,因为外键字段指向哪条数据记录应该由用户决定而不是数据库,另外,外键字段的数据类型尽量与主键字段保持一致,否则where条件的求解过程将变得很慢 。
外键字段是否需要加NOT NULL根据具体情况来决定,大多数情况下,应该加上NOT NULL属性,以防止那些缺少必须数据的不完整记录被插入数据库,如果不关心数据是否完整,那就无所谓是否加上NOT NULL属性。

明天介绍外键的约束条件

精通MYSQL数据库——连载十六

精通MYSQL数据库——连载十六

将数据库转为范式的过程中,需要把一系列数据表关联起来,这种关联用数据库术语来说就是“关系”。一般来说,两个数据表之间的关系大致有三种:
1、1:1关系。两个表之间是1:1,代表了第一个数据表里的每一条记录分别对应着第二个数据表里的一条记录,同时第二个表的记录也分别对应着第一个表中的一条记录,实际工作中,很少见到这种关系,因为既然是1:1,那么证明他们是可以合并为一张表的(但在WEB处理的时候就不是这样,比如用户基本信息,用户扩展信息,他们肯定是1:1的,但如果扩展信息中有TEXT字段,而用户信息又经常被读取,那么我们就会把经常读取的字段分为一张表,不是经常读取的或者是含有TEXT内容的字段分拆为另外一张表,以加快读取速度。)
2、1:N关系。两个表之间是1:N,代表第一个数据表里的一条数据可以对应着第二个数据表里的多条记录。(大多数举例都是用工厂和产品来进行举例,从WEB方面来说,我们可以从用户表来分析,一个用户可以有多条地址簿,家庭、工作单位等,看淘宝在下单时选择地址就知道了)
3、N:M关系。两个表之间是N:M时,代表第一个数据表的一条记录可以对应着第二个数据表里的多条数据记录。同时第二个表中某条记录也可以对应着第一个数据表的多条记录。这里一般是用订单来做介绍:一个订单可以购买多个产品,一个产品也可能存在于多个订单中。

1:1关系
这种类型的表起源通常因为人们把某个数据表拆分成两个使用同一个主键的数据表。把1:1表分拆大致有两种原因,一种是信息安全方面考虑,还有一种就是上文说的效率方面的考虑。

1:N关系
1:N关系是最常见的两表之间的关系了。只要在第一个表的数据记录里有一个特定字段引用了第二个表中的数据列,就会形成1:N关系。
一般来说,1:N有点象1:1表,大多数情况下都是采用主键关联,只有这样才会保证1:N,而不是N:M,例如:分类表与文章表、用户表与地址簿表,论坛主题与跟贴,用户表与订单表,员工表与员工履历表等,这些都属于1:1表。

N:M关系
其实1:N在设计的不太好时,很容易就会变成N:M表。N:N表大致用于订单与产品、用户表与回贴表、员工表与考勤表等等

精通MYSQL数据库——连载十五

精通MYSQL数据库——连载十五

当你需要把分类表显示为树形时,肯定是需要进行一些妥协,就象前面文章中所说的,对数据进行这种处理意味着要无数的SQL查询命令或者复杂的客户端代码打交道。
可供选择的解决方案之一是在分类表中增加两列:sort,deepth,SORT字段负责给出各条数据记录将出现在层次关系树的第几行(假设同一层次的记录将分类名进行排序),DEEPTH字段则负责该分类所在的层次深度。
这种方式的好处是可以通过在MYSQL程序中执行下面这条简单查询的办法得到证明。例如:SELECT CONCAT( SPACE(deepth * 2) ,catename ) as category , sort , deepth FROM categories ORDER BY sort.其中concat函数的功能是把两个字符串并为一个,space函数的功能是生成指定个数的空格字符,AS关键字是给整个表达式起一个新的名字(别名,可能更容易理解一些)。
执行这样的SQL后,可以生成一个简单的树结构,树的尝试都是通过deepth的空格来显示的(这里显示简单的例子)
CATENAME          SORT    DEEPTH
主分类            0       0
一级分类          1       1
二级分类         2       2
重复一级分类         3       1
重复二级分类         4       2
三级分类           5       3
大致结构如上。
那么sort值和deepth的值是怎么来的呢?我们会进行一个简单的演示:
1、新建一个[新的三级分类],它被插入到[二级分类]下一级。而二级分类有关的数据是sort=2,deepth=2
2、那么我们首先要找到[二级分类]下是否已经有数据插入,SQL为:WHERE parentId = [二级分类]ID
3、将数据追加到二级分类下(即SORT+1,深度=)
4、更新相关数值
在这里面就涉及到一些问题,二级分类下如果有多个三级分类,三级分类还有四级分类,这时候SORT值的取值就比较难以控制。插入值后,它的SORT值其实是覆盖了原来的重复一级分类的SORT,那么,原来的SORT值>=当前SORT值的,都需要自动加1.
由此可见,虽然SORT值和DEEPTH值简化了查询工作,但实际上他的写操作变得频繁和复杂了。如果需要更新其中的一条记录,所涉及的操作还会更多。因为他必须要相应的调整sort值和deepth值。
因此,在实际情况中,你必须决定是对读操作进行优化还是对写操作进行优化。一般情况下,对于这种分类表,我都比较倾向于一次读出,然后利用 PHP语言进行深度的处理 也就是说,我是一般不会用SORT和DEEPTH字段的。因为大多数情况下,分类表都是一种比较固定的表,不大会读写,而在后台的读写,也不会影响到前台的操作。。

好象有点乱。

精通MYSQL数据库——连载十四

精通MYSQL数据库——连载十四

分类表是一种典型的层次化关系的表,从数据库设计工作的角度看,让每个分类记录的parentId字段指向它们父分类的Id即可。
把层次关系转化为数据表并不困难,而且层次还相对比较清晰,但在这种表面现象的背后还有许多难题在等待着用户解决。比如,我们无法只用一个简单的SELECT就把指定分类的父分类或者子分类全部查询出来,而必须通过多次查询才能解决这个问题(或者一次查出后,用程序来进行处理)。
事实上,数据库设计和SQL编程有着千丝万缕的联系,很难将他们完全区分开来,再者,如果SQL不足以把想要查询的数据从数据表里提取出来,那么,想拿出一个优秀的数据为设计方案就只能是一句空谈。
想要通过数据表去管理和使用层次关系,得解决很多难题,而这些难题几乎都与SQL语言不能递归查询这一事实有关。以分类表为例:
1、只用一个查询就把指定分类的所有父分类全部查出来是不可能的
2、把完整的数据表还原为层次关系(树状)也是一个难点,还是必须执行多次SQL才能完成。
3、把指定分类下所有子分类全部查询出来
4、设计时,一个分类不能有两个父分类(例如:sql语言既能够放在database分类中,但好象放在programming分类下也行,因此,如果sql语言有两个父分类仿佛才是合理的)
5、层次关系最担心 的是留下循环引用隐患(比如手工删除数据或者添加数据时,很容易导致第4条的情况发生,数据库层次断链或者重复等)
虽然有这些存在的问题,但并非不可解决,而从上面这些难点来说,层次关系往往会导致即使是一个相对简单的问题也需要很多条SQL查询才能得出答案,而且整个过程都相当慢。如果不使用层次关系(或者使用有限的层次关系),上述问题即都可以避免。如果必须使用多级的层次关系,增 加一些数据列或数据表来提供更多关于层次关系的信息,将有助于层次关系的解决方案变得简单一些。
从范式的标准来说,冗余是不对的,它会导致存储空间不必要的浪费,增加数据库内部管理工作的负担,但为了提高应用程序的执行效率,冗余反而是一种相当简明的解决方案,因此,数据库设计其实是一件多方妥协和折中的事。在数据库领域,通往同一个目标的道路往往有好多条,选择其中的任意一条,都意味着作出了这样或那样的妥协。做出什么样的妥协最有利这往往取决于数据库的具体使用情况:什么类型的查询发生的最为频繁?数据需不需要频繁修改?

精通MYSQL数据库——连载十三

精通MYSQL数据库——连载十三

好久好久没有写了。。。重拾起来,确实有点困难,不过,这次是坚持了。

关系数据库的三个范式最早是著名学者E.F.Codd提出来的,后人又在此基础上对大到数学集合理论,小到加设计细节等诸多方面进行了研究和探索。
有些数据库类图书在介绍三个范式时,又在其基础上增加了一些所谓的范式,但这些范式在实践中重要性不大。他们及其相应的规则只是把标准三个范式的所做的事情描述的更细致而己,这些充斥着“实体”、“属性”等专业术语却又彼此大致雷同的教条不仅没有把事情说清楚,反而会让人们更看不出它们与加有什么联系。
如果确实对数据库非常感兴趣,有一些书值得读读(我没有读过,但我现在看的书的原作者推荐):"SQL for smarties","The Practical SQL handbook","Database for mere mortals","SQL-99 complete,really"
当然如果你对读这些书的意向不大(我也意向不大,英文的,估计看不懂),那么如何很快就能上手呢?这里有一些简单的方法:
1、在设计数据库的时候,一定要给自己以充足的时间,如果数据库里已经充满了数据,而且配套的程序也已经开发完成的时候,再发现数据库设计方案还需要修改,那么花费的时间和精力可就太大了
2、如果发现自己给数据列起的名字中有序号,比如field1,field2之类的,则应该提高警惕,这种现象几乎上增加了 是意味着还有更好的解决方案没有想到——再多创建一个数据表
3、在第一时间向数据库输入一些测试用途的数据,而且要尽可能地多包括一些特殊情况,如果数据出现冗余,往往是应该把数据表拆分 的提示信号(但有时候也未必,比如用空间换时间的时候就需要冗余,这点在WEB应用上尤其明显)
4、注意发现和运用各个数据表之间的关联/引用关系
5、掌握SQL语言。缺少SQL编程经验的人是很验证拿出一个优秀数据库设计方案的。把信息存入数据库的目的是为了让更多人能够使用SQL查询命令把它们再迅速准备地查出来。只有了解了SQL查询命令的涉及范围,才能找出把数据分门别类地存入数据库的最佳办法
6、找个示例数据库做为借鉴(这个相对比较重要,比如你要开发论坛程序,那么你应该先找一些开源论坛进行安装,再对他们的数据库结构进行研究和借鉴是最快的学习方法)

精通MYSQL数据库——连载十二

三大范式:第一范式,第二范式,第三范式,听着名字就很恐怖。但其实现在的人都被这个所谓的第三范式折腾死了,有事没事就拿出来涮涮,究竟怎么理解这些呢?一个一个慢慢的介绍。

数据库理论家们为数据库的设计1对N,N对N这种问题总结出了一个通用的解决方案,只需一步一步地三个范式(Normal Form)的规则应用到自己的数据库上就可以了。

第一范式的规则:

1、内容相似的数据必须“消除”(所谓消除,即再创建一个表来存储他们)

2、必须为每一组相关数组分别创建一个数据表

3、每条数据记录必须用一个主键来标识

第一条规则,看上去就比较适用于1对多的情况

第二条规则就不太好控制了,很多人认为第二条规则很难理解,数据的相关度,很难简单的描述清楚

第三条规则其实是一个实践经验,它的意思是数据表里的第一个数据行都应该包括一个独一无二的标识符作为索引。在使用MYSQL的时候,我们大多采用了自增字段来作为主键,但并非只有整数的自增字段才能作为索引,只要是独一无二的数据列,都可以用来做索引,之所以采用自增列,那是因为:1、不需要主动插入值2、整数列的时间和空间效率相对比其他类型的要高。

第二范式的规则:

1、只要数据列里的内容出现重复,就意味着应该把数据表拆分为多个子表

2、拆分形成的数据表必须用外键关联起来

第二范式,其实是在第一范式的基础上再进行一个拆分。指的就是第一范式规则的第二条内容。

外键关系在第二范式里显得特别重要,是因为第二范式时,数据会拆得更细,如果没有外键关联,恐怕数据就找不回来了。外键相当于我们日常所说的:交叉引用,对开发人员来说相当于指针。

第三范式的规则

第三范式只有一条规则:与主键没有直接关系的数据列必须“消除”

其实也就是把第二范式再分解,再建表。

可想而知,等到真正把一堆数据完全按照第三范式来进行设计的时候,恐怕在数据库里也就只能看到一堆ID了,数据呢?数据在哪里?通过外键,外键的外键,外键的外键的外键来慢慢的一个一个搜索吧。

对于MYSQL 4.1以下的版本,第三范式是会要了他们的命的,foreign key功能的不完善,让MYSQL 4.1以下版本,基本不适合第三范式,能用到第二范式设计时,数据表的效率已经几乎不能保证了。

这三个范式是著名学者E.F.Codd最先提出来的,后人在此基础 上对大到数学集合理论、小到关系数据库设计细节等诸多方面进行了研究和探索。如果对这方面有兴趣的朋友,还是多找找相关的书籍看看为好。

如果你的性子比较急,那么你可以尝试按照下面的方法来进行:

1、设计数据库的时候,一定要给自己充足的时间,如果等到数据库充满了数据,而程序也几乎开发完毕时,才发现数据库设计有缺陷,那么花费的代价就太大了

2、如果发现自己创建的表的数据列有序号,如name1,name2等,那一般就意味着还有更好的解决方案没有采用。可以考虑多创建一个表,而把这些分拆开。

3、第一时间往数据库里多插点测试数据,如果发现冗余量很大,往往就是表需要分拆的信号

4、设计时应该注意数据与数据之间的关联及引用关系

5、对于设计完的数据库,应该自己尝试写SQL语句,看看能否达到你预想的目标,如果达不到,那就要考虑是否设计的有问题。

6、如果你还是等不急,根据你的需要,到网上找找有没有类似的示例数据库,可以考虑拿来作借鉴。

说了这么多时间的范式,最后再说说他们的优缺点吧

缺点:数据表的个数越多,也就相对证明了从表单里获取数据并往表里插的时候,复杂性非常大,给开发人员会带来很大的困扰。同样,表多了,查询结果时,从中提取相关数据生成查询结果的复杂性也就越大;数据库的容量随着表的拆分量的增大而增大(不过现在也不是什么矛盾了,硬盘的价格几乎也快到了白菜价了,这点可以被忽略)

优点:严格按照范式设计出来的数据库,能够提供最丰富、最灵活的查询选项,人们往往都是在等到必须使用一种新的查询或者必须对数据进行一种新的分类时才会真正意识到这一点,但可惜的是,这些新需求往往都是出现在数据库已投入运行数月之后,到时候再改数据库,代价非常大。


现在工作有点忙,连载不会忘记,但更新频率会放慢,毕竟全部都是手工打出来的字。

不会象写小说那样太监掉的,毕竟这个东西对我自己来说,也是一种学习

给自己加油,为自己打气。也谢谢大家的支持

精通MYSQL数据库——连载十一

精通MYSQL数据库——连载十一

一个好的数据库设计应该符合以下几点要求:
1、数据表里没有重复冗余的数据(如果总是往里面插入同样的数据,那应该是设计上有问题,当然现在在利用空间换时间的时候,多数人还是保留了这样的想法)
2、数据表里没有column1,column2,column3……这类没有明确意义的字段,因为这样会让后来人摸不清头脑
3、数据表占用的空间越小越好
4、使用频率高的数据表的查询,应该都能以简单高效的方式执行(表内数据少的时候,你就是10几个left join,你可能都感觉不出什么,但数据量一大,你一个left join都会让你感觉到速度慢下来,如果最初设计时没有满足这个要求,那么,以后想改可能也没有机会了)
这些也只是一些总的原则,也只是简单的介绍,以后会详细说明,当然上面这几点并非完全正确,就象第三范式,这是一个标准,但这个标准真的就是最好的吗?并非如此,但我们现在是在讲设计数据库,它好不好,目前不讲。以后一起讨论

为MYSQL的数据库和数据表甚至字段起名字还是有讲究的,最重要的是,千万不要使用保留关键字,而且有一些单词很奇怪,在4.0里面并不是关键字,但升级后,却变成了关键字。
详细的关键字列表请看:MYSQL手册中保留字部分
对于一个完整的设计应该注意以下几项:
1、由于MYSQL对数据列的命名不区分大小写,而对库名和表名区分大小写,因此为了规范和统一,请使用同样的规则,不要象程序代码那样来个骆驼命名啥的,这样只会给开发带来困难,建议是全部采用小写,移植、升级都方便
2、不要采用特殊字符或者中文,MYSQL对于多字节的处理并不十分完美,虽然支持中文建库、建表等,但实在不建议使用,如果你的服务器对中文支持不好,可能建库的时候就会是乱码,字段里,明明看到有值就是查不出,所以,为了规范,还是采用英文,26个字母的排列组合,没有那么复杂的。
3、数据库、表、字段的长度请不要超过64个字符,
4、表名和数据列名,请尽量采用有意义的名称,不要出现上文提到的那种column1,colnmn2之类的,时间长了,你自己都可能不知道是什么意思
5、给字段命名,需要有规范,因为这样会减少粗心带来的错误,比如username,user_name,如果分在各个表里,恐怕你每次写程序的时候,都得再检查一遍吧?对于由多个单词组成的字段,要么全部加下划线,要么全部不加,这样也比较有利于开发和维护
6、数据列的单复数,原因和5一样,要么全部单数,要么全部复数,一会单数一会复数的,开发和维护的时候,你就得盯着数据表来进行了。

数据库的设计是一件很复杂的事情,要在短时间内把一批数据分割开,并存储到数据库中,还得为开发人员提供足够的优化空间,不是一天两天就能完成的,当然现在有很多这样的工具,比如powerdesign(PD),在设计完后,还能导出数据库,确实是挺方便,但这样的软件,价格就太高了,不是我们所买得起的。
平时,我们还是使用WPS的电子表格,或者openoffice的电子表格功能,设计好数据表(电子表格最大的好处就是有几乎无穷的sheet,可以让你把一个很大的库放在这些sheet里),而且,几乎每台电脑上都会有这样的工具,便于交流。这样可以在最初的阶段对于一些数据列进行安排(没办法建立索引的,只是简单的用来布局,检查设计上是否有缺陷)

对于管理MYSQL,也有很多工具,比较常见的,就是:phpMyadmin;MYSQL自已也提供过,好象是mysqlFront?记不太清,现在我自己用的是navicat for mysql lite ,不用钱的东西都是好的。虽然在国内,大家都了解软件业的行情。自己也处于软件业的下游,能够使用正版,还是使用一下正版吧。不能使用正版的,找找免费版。
在我看的书上,它介绍说openoffice里其实还隐藏着连接数据库这个功能的,而且可以能够象创建视图一样来创建SQL,这个功能不错,我以后要好好看看,如果确实有用,那我WPS也不装了,直接使用openoffice。
不过,最常用的,最方便的,还是使用phpmyadmin,它实在是居家旅行、杀人灭口之大杀器。

精通MYSQL数据库——连载十

本来觉得二进制字段没有什么好介绍的,本来嘛,二进制字段,不就是xxxtext变成了xxxblob?长度,大小都没有变化,只是存储的类型变成了二进制,如果把那些xxxtext字段的属性加一个binary,那就和xxxblob差不多了。
只是在没有加上binary属性的时候,xxxText字段的排序和比较是按字符串类型处理,而xxxBlob是按二进制处理的。加了BINARY属性自然是一样的。
关于在数据库里存在BLOB信息,历来就是一个有争议的话题。最早的VBB论坛就是把附件存在数据库里的,后来还有人单独做HACK把附件剥出来。很多人认为数据库就应该存储一些文本信息,对于二进制数据(图像、附件等)就只应该存储链接,而把文件单独存储出去。这样可以更加有效的利用数据库的空间。
但支持把附件存储在数据库的人却认为,二进制数据存储在数据库内,有利于数据的迁移、备份,提高了数据的集成程度,而且在程序里也能够使用统一的形式访问数据。把常用的数据和这些二进制数据存储在同一个表内,一般被DBA们所痛恨,因为这会导致所有的数据记录的存取速度变慢,而且BLOB数据在正常操作情况下只能作为一个整体来读出。也就是说如果一个BLOB数据长度是1024KB,如果你仅仅想读最后那24KB的内容,没有直接的办法,只能先读出来,然后再定位到最后,BLOB数据只能以一个整体来读写和传输。
从5.0.3开始,原来的BIT型字段正式变形,成为二进制字段了,它的最大宽度达到了64,为了这个BIT型字段,MYSQL还特地增加了一条用来写出二进制数据的新语法:b'0101',SELECT查询的时候,遇到BIT型,将返回二进制数据。(我没有5.0.3的版本,没有测试过怎么读取,书上介绍,可以先使用 seelct bit_field + 0 命令把二进制转为整数,再使用select bin(bit_field + 0 ) 将这些整数显示为二进制)
对于二进制来说,数据会有溢出现象,它分为上溢出和下溢出,但不管是如何的溢出,只要是溢出了,所有的二进制位都将被设置为1。例如将-1,0,1,7,8五个数字依次存入BIT(3)数据列的时候,实际存放的是b'111',b'000',b'001',b'111',b'111'。
除开这些二进制字段,剩下的就是具有MYSQL特色的字段了,如果没有什么必要,确实不太建议使用,因为其他的数据库都不支持这两种类型,一旦在数据迁移的时候,很有可能会造成丢失或增大工作量,是什么字段呢?他们就是ENUM和SET(枚举和集合)。
对于MYSQL来说,这两种字段对于涉及字符的操作,有很高的效率,表面上存储的可能是文本,但在实际处理的时候,是按设置的下标来进行操作,即按INT类型操作,所以效率极高。
ENUM是一个字符串集合,它的成员最多可以有65535个,ENUM字 取值只能是这个集合中的某一个成员(不允许是不同成员的一个组合 ),相当于数学意义上的“排列”。
而SET虽然采用了类似的思路,但允许数据表中的SET字段的取值是集合成员的任意组合(组合数量不得超过64个),相当于数学意义上的“组合”。在内部,这些字符串分别与2的幂(1,2,4,8等)相对应,所以字符串的组合就相当于二进制位的组合 。因为每个安符串分别对应一个二进制位,所以SET类型的空间战胜比ENUM大。
虽然这两种类型的效率相对较高,但由于和其他数据库的不兼容性,因此多创建一个关联数据表来关联这些数据才是更有实用价值。


介绍完MYSQL所支持的所有字段的属性,也该介绍一些在创建数据列的时候涉及到的属性,注意,有一些属性只能用于特定的数据类型

属性名 含义
NULL 数据列可以NULL值(一般是默认设置)
NOT NULL 不允许包含NULL值(因为bTree索引不支持NULL)
DEFAULT xxx 如果输入时没有指定值,则默认以xxx为值
DEFAULT CURRENT_TIMESTAMP 这个在介绍日期时间类型的时候介绍过,默认插入当前时间
ON UPDATE CURRENT_TIMESTAMP 在数据更新的时候,自动更新为当前时间
PRIMARY KEY 定义为主键
AUTO_INCREMENT 自动输入一个序列编号,只能用于整数类型的数据列,一般与主键对应使用,必须与NOT NULL,或UNIQUE 属性同时使用
UNSIGNED 无符号整数,值得注意的是,无论怎么计算,即使是1-2,返回的也是无符号的整数
CHARACTER SET name 仅适用于字符串列,指定一种字符集和一种可选排序方式


虽然MYSQL有DEFAULT XXX这种属性,但实际上,MYSQL并不允许使用函数来设定默认值,比如DEFAULT rand()就不被允许了。

介绍完这些,以后就该介绍数据库的设计技巧了。之所以在介绍设计技巧之前连载了这么长时间的数据类型,是因为在设计中,使用合适的类型可以适当的增加效率,具体的还是看设计吧。

精通MYSQL数据库——连载九

字符串,恐怕应该算是MYSQL里面最复杂的类型了吧?几乎目前所有的问题,都是出在与字符有关的数据列上,大致有几种
1、字符串的查询(以下如果不特指,都是指中文),搜索一个中文的时候,不管是模糊还是精确,往往结果都会有与搜索内容不一致的数据在里面
2、编码,现在大家都知道MYSQL连接上后,先执行一下mysql_query('set names GBK',$conn)这类的语句,从MYSQL4.0升级到4.1及以上版本的朋友在这上面吃的苦不少了。网上关于这类的提问也是最多的
3、索引、效率,varchar是MYSQL所特有的字段,而且长度可变,char则是固定长度的字符串。
在MYSQL所支持的几个字符串格式里面,char和varchar是用的最多的,char是定长字段,,也就是说,不管字符串的实际长度有多少,CHAR(10)将永远占用10个字节。字符串如果前端有空格,那么在存储的时候会自动被数据库去掉,相当于先执行trim($string),再进行存储,如果不满10个字节,将会采用空格填满,读取数据时,MYSQL会自动将这些空格去掉。看到这里,恐怕它的缺点之一就明显的暴露了,CHAR不能存储那些结尾确实有空格的字符串(因为读取时会被MYSQL自动去掉)。


数据类型 含义
char(n) 固定长度的字符串,最多255个字符
varchar(n) 可变长度字符串,最多255个字符(MYSQL<5.0.3,n<=255 , mysql>=5.0.3,n<=65535)
tinytext 可变长度字符串,最多255
text 可变长度字符串,最多65535-1
medinumtext 可变长度字符串,最多16,777,216-1
longtext 可变长度字符串,最多4,294,967,296-1

除了char类型外,其余类型均为可变长度,实际所占空间由该字段所存的内容决定。虽然varchar与tinytext一样都是255个字节,但不同的是varchar可以指定存储的长度,而tinytext只能由存储的时候数据长度而定。
在数据表被创建的时候,MYSQL 把数据列的定义改成一种对MYSQL来说更有效率的形式。这种自动方式的修改称为默许的数据列修改(client column changes)。一般来说是对CHAR和VARCHAR数据列都有影响:如果n<4,varchar(n)将被修改为char(n),而如果n>3并且在同一个数据表里还有其他的可变长度的字段,char将被修改成varchar格式。如果数据表里只有固定长度的数据列,char列将不发生变化。也就是说,你在数据表里的字段如果有多种格式,那么你通过alter table 是无法进行修改的。
上表提到,varchar在新版本里变成了65535个字节,但最大字符个数还是要取决于具体的字符集(GBK中文占两个字节,而UTF8中文则占三个字节)。上面这些所有的数据类型都有一个BINARY属性,一旦该字段添加了这个属性,那么MYSQL就会将他们视同BLOB字段来处理。BINARY的好处是在排序时把字符视为二进制,这样就可以把字母的大小写分开,而且由于是二进制字符串,所耗费的时间也会更短。可惜,在实陆应用中我们存储的大多是中文,所以这一点对我们来说并没有太大的区别。中文,本来就没有大小写之分,再怎么二进制,还是那样。呵呵。
在MYSQL4.0及以前的版本里,各种文本字段的字符集和排序方式都由MYSQL服务器决定,默认值是latin1字符集和瑞典排序方式。虽然允许在MYSQL配置文件里指定一种字符集和排序方式,但这会导致所有的数据库受到影响,还有,对字符集和排序方式做了任何修改都必须重启数据库服务器方能生效,更可恨的是,重启后,还必须重新创建所有的索引,同时,MYSQL4.0之前的版本并不支持UNICODE字符集。
4.1后,这些问题得到了很大的改状况,可以单独为某一个数据列指定一种字符集和排序方式,而且字符集和排序方式的选择范围也大了很多,因为从4.1开始支持了UNICODE和UCS-2等。与字符集及相关排序方式相关的命令是:SHOW COLLATION(必须要注意的是,字符集和排序方式不是随意组合的,每种字符集都有该字符集对应的一些排序方式,而不能混用)。如果没有为某个数据列指定一个字符集和排序方式,它将使用数据表、数据库或MYSQL数据库的默认字符集。至于数据库应该使用哪种字符类型,还是由你的项目所决定,如果你的项目采用了GBK编码,那数据库也同样使用这种编码比较好。如果你在项目初始时对于采用哪种编码未知,那么UTF8应该算是比较好的一种解决方法,数据迁移以及对于JAVA、.net等程序的支持也是最好的,唯一的缺点就是占用数据库空间太大。
说到现在,一直在说latin1和unicode字符集,这代表了什么意思呢?
latin1:在最初的MYSQL版本里都是默认采用了这种字符集,它是符合ISO-8859-1的规范的,收录了西欧国家的常用字符,在那个年代,国内还没有多少人使用MYSQL,而真正使用这些的大多是欧美国家,所以这个字符集主要就是用于收集这些国家常用的字符。随后latin的标准 在不停的变化,有latin2,latin9等,但它们当中并没有一个能够把所有欧洲语言里所有的字符都收录齐全,也就是说latin库里并没有一个可以适用于整个欧洲。
UNICODE:正由于latin不能解决这个问题,所以人们开发出了双字节的UNICODE字符集,两个字集意味着是2的16次方,可以存储65535个字符,所以UNICODE字符集不仅涵盖了所有的欧洲语言,还覆盖了绝大多数的亚洲语言。然而UNICODE只定义了每个字符的编码,没有定义如何存储这些编码。
在这个基础上,也同样发展出了好多变体。最重要的是UCS-2和UTF8,UCS-2又称UTF-16,即每种字符都用两个字节表示,所以几乎所有的字符都被涵盖了。但是这种也是有弊端的:存储空间大了一倍,即使是ASCII字符也是这样;字节编码0会出现在字符串中(比如ASCII写出来的文本里,每一个的第2个字节都是0),可是一些程序会把0当成结束标志,而导致出错。
UTF8是UTF16的替代品,在这里所有的ASCII(7位)仍然象以前一样用第一位是0的单字节表示,所有其他的UNICODE字符用2~4个字节表示。它的缺点也同样明显:同一份文档的字节数和字符数没有任何显而易见的关系,但由于它与现有的程序高度兼容,所以UTF8几乎已经成为了一种事实上的标准,而且大多数软件都把它作为自己的默认字符集。
可惜,PHP发展到现在对于UNICODE的支持还是一般性,并没有内置,处理的时候,不是用ICONV就是mb_string库(PHP6是说内置支持了),但并不能妨碍我们使用UTF8来开发网页。

字符串就介绍到这里。太累了。。。。。这个方面的问题太多了,在以后的连载中遇到再详细说明吧。