<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ChenTaoqian&#039;s Blog &#187; mysql</title>
	<atom:link href="http://www.chentaoqian.com/archives/tag/mysql/feed" rel="self" type="application/rss+xml" />
	<link>http://www.chentaoqian.com</link>
	<description>主机,企业邮箱,域名,空间,服务器,Java,Oracle,PHP,Linux,JS,MySQL,Apache</description>
	<lastBuildDate>Wed, 30 Nov 2011 14:35:01 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>MySQL数据量对innodb索引使用的影响</title>
		<link>http://www.chentaoqian.com/archives/595</link>
		<comments>http://www.chentaoqian.com/archives/595#comments</comments>
		<pubDate>Thu, 06 May 2010 12:36:58 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[innodb]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[索引]]></category>

		<guid isPermaLink="false">http://www.chentaoqian.com/?p=595</guid>
		<description><![CDATA[从开始使用mysql起， 就觉得：
1. 索引的使用对innodb的性能的影响是很大的， 在做explain的时候， 当extra中出现了filesort的时候一般就意味者低效率和应当优化sql语句
2. 在select语句中， where中用到的条件字段order by中的字段最好是同一个(些)字段(假定只有都只有一个(些)字段)， 且这个字段最好是有索引的， 这样在explain的时候， type就会是index, 且extra中不会有filesort; 如果where中的字段和order by的字段不一样的话， 则可能出现filesort, 从而会导致低效
在实际中遇到了一个例子， 发现上面的理解其实是比较片面的， 这个例子的大体情况是：
表t_mytable中有字段F_time_1和F_time_2,分别是datatime， 且分别都有索引；字段F_pid是主键
1. 运行sql语句 SELECT &#8230; FROM t_mytable WHERE F_pid=&#8217;val&#8217; AND F_time_1&#62;= &#8216;time1&#8242; AND F_TIME_1 &#60;= &#8216;time2&#8242; ORDER BY F_time_1， 记录条目是12条， 但发现效率很低；觉得很奇怪：这个语句的效率应该高才对的
2. 尝试着改了一下sql语句为SELECT &#8230; FROM t_mytable WHERE F_pid=&#8217;val&#8217; AND F_time_2&#62;= &#8216;time1&#8242; AND F_TIME_2 &#60;= &#8216;time2&#8242; ORDER BY F_time_1，记录条目是8条，效率很高；

效率上的差别让人觉得有些奇怪， 觉得是违反一直以来的直觉的， [...]]]></description>
		<wfw:commentRss>http://www.chentaoqian.com/archives/595/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL理解innodb的线程模型</title>
		<link>http://www.chentaoqian.com/archives/593</link>
		<comments>http://www.chentaoqian.com/archives/593#comments</comments>
		<pubDate>Wed, 05 May 2010 14:10:15 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[innodb]]></category>
		<category><![CDATA[mysql]]></category>

		<guid isPermaLink="false">http://www.chentaoqian.com/?p=593</guid>
		<description><![CDATA[第一部分， innodb的线程模型：
innodb内部大体上有三类线程， 主线程（只有一个）； 用户线程 ， 用户线程根据不同的职责也可以分成两类； 辅助线程
整个innodb由一个主线程控制， 这个线程是innodb一起来的时候就开始运行（入口函数是srv_master_thread）， 它的优先级相对于其他innodb内部的线程来说优先级较高， 大部分时间下， 这个线程处于sleep状态， 每隔一定间隔这个线程起来看看是否有什么任务需要处理，这些任务包括:
1. drop延迟删除的表(如果有的话)
2. 把日志缓冲区(log buffer)中的日志(如果有的话)通过同步写的方式flush到硬盘
3. 检查缓冲控制区的完整性
4. 把缓冲区(buffer pool)中的数据写入到硬盘
5. 插入缓冲区(ibuf)的合并(merge)
6. binlog的purge
7. 生成检查点(checkpoint)
innodb运行了一些处于normal优先级的被称作用户线程的线程，大体分成二大类：
一类是包括专门负责处理客户端请求的线程， 处理控制台请求的线程等；每个用户线程负责一个客户端的请求， 其完成的工作包括接收输入， 启动处理过程， 当查询处理完成后负责把结果返回给客户端；也就是说， 没有专门的负责通信的线程和专门负责处理的线程之分， 这样做的好处是少了一些线程的切换开销，个人觉得，这个节省到底有多大和必要是和机器的状况， 客户端的数量， 客户端所处的位置相关的；另外， 这种模型在客户端多且请求频繁的情况下对于设置并发线程(innodb的并发模型后面会谈到)的上限来说比较困难； 顺便提一下， mysql客户端和服务器的通信时单工的， 所谓单工， 就是会出现服务器端和客户端同时发送信息给对方的情况。
第二类线程是负责执行sql语句的线程， 这些线程会把sql请求分解，然后执行， 待执行完成后， 通知客户端线程(第一类线程)来返回数据
辅助线程， 完成一些辅助工作， 比如异步读写线程， 负责插入缓冲区flush的线程和负责日志flush的线程等
innodb维护有一个线程表的数据结构来管理所有的线程， 其中记录了线程的状态信息，用来控制挂起的信号量等.
innodb的&#8221;线程调度器&#8221;
innodb自己实现了一个&#8221;线程调度器&#8221;: 在同一时刻， 只允许一定数量的处于活动状态的并发线程位于innodb内核， 全局变量srv_thread_concurrency(变量innodb_thread_concurrency)控制着这个数目，
对于一台4cpu, 4disk的机器， 推荐的srv_thread_concurrency是10， 这样做的目的是尽量减少不必要的线程切换； 对于srv_thread_concurrency来说，0是个特殊值， 用来表示不进行任何并发线程数量的控制； 当然， 处于等待状态的线程（等待某些资源的进程）是不算在内的， 因为如果这些都算的话， 可能会导致死锁。 当一个线程试图进入innodb内核时， 都会调用函数srv_conc_enter_innodb来取得进入innodb的许可，如果当前处于内核的线程数目达到了上限，且这个线程所进行的事务没有占用资源的话（这样做的目的是为了防止死锁）， [...]]]></description>
		<wfw:commentRss>http://www.chentaoqian.com/archives/593/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mysql的innodb缓冲池管理(二)</title>
		<link>http://www.chentaoqian.com/archives/590</link>
		<comments>http://www.chentaoqian.com/archives/590#comments</comments>
		<pubDate>Tue, 04 May 2010 08:46:03 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[缓冲池]]></category>

		<guid isPermaLink="false">http://www.chentaoqian.com/?p=590</guid>
		<description><![CDATA[页面读入机制
当读入页面的时候， 首先需要找到一个可用的block， 这个block或者来自于free list或者lru-list; 在读入数据块的时候， block会加上排他锁以防止其他线程再次使用这个block，
会在block中标记出这个块正处于io状态， 然后把io请求加入到io调用请求对列； 完成读入操作时， 再释放block上的拍它锁更新io状态。
数据页面的读取写入
缓冲池中的数据基本是采用同步aio的方式，这里的同步aio的意思是： 工作线程发出读或写请求后，请求会被放到一个读写请求队列中，由专门的io线程负责写盘和读盘，而工作线程则等待io的完成，
注意， 这里是等待完成，而不会放弃执行，因而称作为同步aio.
提前读(预读)机制
为了优化数据读入性能， 缓冲区读入采取了提前读的机制（当然，这个机制可以配置成不激活），当然， 提前读的机制是基于数据局部性的原理来的，
这就是为什么采用取值过于随机的字段作为主键会导致性能降低的原因之一：过于随机的主键会导致提前读不起作用， 而且会导致更多的换页行为； 这个预读取对于上层的功能如索引管理是透明的，
对于上层的功能来说， 需要提供的信息是需要读取的页是否有后继页和前置页。 有两种预读机制: 线性预读和随机预读
线性预读： 当第一读缓冲区中某一个已经存在(注意，这里必须是已经存在于缓冲区额数据块)的数据块时， 会检查这个数据块是不是处于所谓的线性预读区域(比如， 区域大小是64， 当前读入的也是100，那么所在的预读区域是65 ~ 128)，如果是， 则统计一下这个区域中目前没有被访问过的页面，如果数量多于预读机制设定的预读数量，则放弃本次预读， 这个其实是检查目前的区域是否还有大量的页面没有被访问过， 如果是的话， 自然没有必要去做预读了； 否则， 取得读取页面的后继页和前置页(按照数据页的自然顺序?，然后检查后继页或者前置页是否是一个新区域的边界，如果是， 则发出读取
该区域里面的数据页面的异步请求。
随机读: 当读取一个页面时， 根据所读取页的位置计算出该页面所在的随机预读区域， 区域的计算也基于设定的区域页面数量来计算的(如前面关于线性预读的例子)， 然后根据lru对列的信息计算该区域中有多少块最近被访问到了， 如果被访问的数量达到一定的额度(这个额度是根据预读区域的大小计算出来的， 5 + 预读区域大小 / 8)，则预读取该区域中目前还没有读取到缓冲区的块.
show innodb status 中关于buffer pool的输出
Buffer pool size 262144 整个缓冲池中的页的数量， 包括flush列表中的和flush列表中的，以及被分配出去的页的数量
Free buffers 0           free列表中的页的数量
Database pages 258053    分配出去， 正在被使用页的数量
Modified db pages 37491 flush列表中的数量
Pending reads [...]]]></description>
		<wfw:commentRss>http://www.chentaoqian.com/archives/590/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mysql的innodb缓冲池管理(一)</title>
		<link>http://www.chentaoqian.com/archives/587</link>
		<comments>http://www.chentaoqian.com/archives/587#comments</comments>
		<pubDate>Mon, 03 May 2010 09:11:41 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[缓冲池]]></category>

		<guid isPermaLink="false">http://www.chentaoqian.com/?p=587</guid>
		<description><![CDATA[在数据库数据处理中， 缓冲在改善性能方面扮演着很重要的角色， 为了保证性能， innodb 维护了自己的缓冲池。 文章大体介绍一下innodb缓冲区实现和管理策略。
在innodb中，需要用到数据页(需要保存到磁盘的数据)均是从这个缓冲池里分配出来的， 因此，可以说，缓冲池在对innodb的性能有很大的影响。
几个基本的概念
AWE:地址窗口化扩展,允许在 32 位版本的 Windows 操作系统上使用 4 GB 以上的物理内存。最多可支持 64 GB 的物理内存。更多信息请看 http://baike.baidu.com/view/1390438.htm； innodb是支持AWE内存管理的
Frame；帧，16K的虚拟地址空间， 在缓冲池的管理上，整个缓冲区是是以大小为16k的frame(可以理解为数据块)为单位来进行的，frame是innodb中页的大小。
Page: 页，16K的物理内存， page上存的是需要保存到磁盘上的数据， 这些数据可能是数据记录信息， 也可以是索引信息或其他的元数据等；
Control Block：控制块，对于每个frame, 有一个block， block上的信息是专门用于进行frame控制的管理信息， 但是这些信息不需要记录到磁盘，而是根据读入数据块在内存中的状态动态生成的， 主要包括： 1. 页面管理的普通信息，互斥锁， 页面的状态， awe（windows平台上awe机制的管理信息)等 2. 脏回写(flush)管理信息3. lru控制信息 4. 快速查找的管理信息， 为了便于快速的超找某一个block或frame， 缓冲区里面的block被组织到一些hash表中; 缓冲区中的block的数量是一定得， innodb缓冲区对所管理的block用lru策略进行替换。
互斥访问
缓冲池的整个缓冲区有一个数据结构buf_pool进行管理和控制， 有一个专门的mutex保护着， 这个mutex是用来保护buf_pool这个控制结构中的数据域的， 并不保护缓冲区中的数据frame以及用于管理的block, 缓冲区里block或者frame中的访问是由专门的读写锁来保护的， 每个block/frame有一个。在5.1以前， 每个block是没有专门的mutex保护的，如果需要进行互斥保护，直接使用缓冲区的mutex, 结果导致很高的争用； 5.1以后，每个block有一个mutex对其进行保护， 从而在很大程度上解缓了对buf_pool的mutex的争用。
缓冲池管理用到的几个重要的列表
在缓冲区的管理中， 有几个重要的block列表(双向链表)：
LRU列表： 用来进行lru管理的列表， 列表里的每个block所控制的数据都是当前有效的数据；列表中的block基本是按照访问的顺序排列的；最近被访问的放在最前面， 最先被方位的放在最后；lru列表中维护中维护了一个LRU_old, [...]]]></description>
		<wfw:commentRss>http://www.chentaoqian.com/archives/587/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mysql的innodb同步管理</title>
		<link>http://www.chentaoqian.com/archives/585</link>
		<comments>http://www.chentaoqian.com/archives/585#comments</comments>
		<pubDate>Sun, 02 May 2010 11:41:27 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[innodb]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[同步]]></category>

		<guid isPermaLink="false">http://www.chentaoqian.com/?p=585</guid>
		<description><![CDATA[innodb的同步管理
数据库是支持多客户端同时连接和处理的， 因此多线程是必然的，多线程编码很重要的一个方面是处理同步和互斥，innodb的互斥机制有两个：mutex和rw-lock; 当某个线程需要获取一个mutex或rw-lock时，有两种结果可能发生， 一是直接获得了mutex从而继续处理；一个是无法获得mutex只得等待拥有线程释放mutex. 多线程编码技术中， 是通过信号量来通知等待线程mutex的可用性的， mysql在处理时并没有直接使用操作系统提供的信号量机制， 而是实现了自己的信号量机制，之所以不用操作系统的信号量机制而自己实现的主要原因是操作系统的信号量机制比较慢，其次一个原因是(某些)操作系统的信号量处理往往导致线程切换，而在很多时候， 有比不做线程切换更高效的事情：在多处理器系统上，通过循环等待旋转锁(spin lock)， 当然， 在只有单处理器的系统上，循环等待明显是低效的事情。再一个原因是， 便于分析同步情况， 从而避免死锁， 因为当所有的同步信息交给操作系统处理时， 就难以分析死锁情况了，如果有自己的数据结构来管理这些信息， 死锁情况就容易分析。
在Innodb内部， 信号量机制是通过一个叫做等待数组的东西来管理的， 这个数组全局唯一的， 而且同时支持innodb内部两种主要的互斥工具mutex和rw-lock； 数组中的每个数组元素都与一个互斥锁或者rw-lock关联， 和一个事件对象关联； 当一个线程需要等待某一个互斥对象的时候而又无法得到时， 先预定一个元素， 然后把自己挂在这个元素关联的事件上， 直到这个事件被通知。当通过使用等待数组来控制同步时 ，拥有同步对象的线程可以知道哪些线程正待等待， 从而在条件合适的时候发出通知，到达避免死锁的母的。
innodb在互斥资源(mutex或rw-lock)获取管理机制上， 是通过一个多阶段等待机制来等待的；首先， 线程通过循环等待旋转锁来等待(即循环检查mutex是否可用， 当然每次检查是有时间间隔的，通过变量srv_spin_wait_delay控制)，如果在设定的循环次数(innodb_sync_spin_loops配置变量控制)内无法得到资源，线程将会通过等待数组机制来等待：从等待数组中获取一个元素， 并把自己挂在相应的信号量上。当持有mutex的线程释放它的时候， 系统会通知等待在与这个mutex绑定的事件上的所有线程。
通过旋转锁等待机制，可以一定程度上减少线程上下文切换，但是会浪费一些cup， 对于数据库来说， 尤其是在多cup系统上，主要瓶颈在于io而不是cpu, 这种旋转锁机制的总体效率是不错的。
在show innodb status的SEMAPHORES那里看到得一些信息来印证一下innodb同步系统：
OS WAIT ARRAY INFO: reservation count 28772, signal count 28374
系统中的等待数组中有28772个元素被预定了 ，有28374过有过信号量的通知
Mutex spin waits 0, rounds 794773, OS waits [...]]]></description>
		<wfw:commentRss>http://www.chentaoqian.com/archives/585/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mysql的排序机制</title>
		<link>http://www.chentaoqian.com/archives/582</link>
		<comments>http://www.chentaoqian.com/archives/582#comments</comments>
		<pubDate>Sun, 02 May 2010 05:26:06 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[原理]]></category>
		<category><![CDATA[排序]]></category>
		<category><![CDATA[数据库]]></category>
		<category><![CDATA[机制]]></category>

		<guid isPermaLink="false">http://www.chentaoqian.com/?p=582</guid>
		<description><![CDATA[在查mysql的排序问题时， 了解了一下Mysql的排序机制， 大体是：
mysql把需要排序的地方都叫filesort， 名字上看有个file在里面，但不一定与文件有关， 可能就是在内存完成的排序。
MySQL 有二个 filesort 算法， 第一个方法(原始方法)只使用了ORDER BY中指定的字段。第二个方法(改进的方法)不仅使用ORDER BY中指定的字段，还是用了查询中所涉及到的所有的字段。
优化器决定选择哪个filesort 算法， 除了查询中涉及到TEXT或者BLOCk字段外，它通常使用改进的算法，当查询中涉及到TEXT或者BLOCk字段时，通常使用原始的方法。
原始的 filesort 算法的工作机制大体是(典型的外排算法)：
1.   通过主键扫描或表扫描读出所有的数据记录，不相配WHERE条件的记录被跳过。
2.   对于每条记录，储存一对信息（主键和指向记录的指针）到查询缓冲区，缓冲区的大小是 sort_buffer_size 系统变量控制的。
3.   一旦缓冲区满了，对缓冲区中的数据做一次 qsort（快速排序）并把排序结果保存到一个临时文件。（如果所有记录信息能放到缓冲区中，就没有必要存到临时文件了)
4.   重复前述的步骤直到所有的记录都处理了完。
5.   每在合并缓冲区中做多路合并， 并把合并后的结果输出到另外一个临时文件
6.   重复多路合并排序， 直到所有的记录信息能分到15个以内的有序集合。
7.   在最后多路合并中，只有指向记录的指针被写到一个结果文件。
8.   根据结果文件中的记录指针的读取出记录放到返回集合中， 这个结果缓冲区的大小是 read_rnd_buffer_size 系统变量设置的。
这个排序算法有几个问题值得注意：
1. 它需要读取记录两次：第一次是执行的WHERE时候，第二次是在对key进行排序之后。 尽管第一次是读取时记录是连续读取的（比如表扫描）, 第二次就是随机读取了。（这时候键值是有序的了，但是记录还不是)
2. 使用到了快速排序，也就是说，排序结果是不稳定的
改进的 filesort 算法在原始的算法的基础上做了一些优化： 在排序时，不只是对键值进行操作，还带有记录位置和查询中需要的字段信息，这避免两次都记录。改进的 filesort [...]]]></description>
		<wfw:commentRss>http://www.chentaoqian.com/archives/582/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mysql主从同步延迟受到机器系统时间的影响</title>
		<link>http://www.chentaoqian.com/archives/569</link>
		<comments>http://www.chentaoqian.com/archives/569#comments</comments>
		<pubDate>Sat, 01 May 2010 00:42:22 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[同步]]></category>
		<category><![CDATA[数据库]]></category>

		<guid isPermaLink="false">http://www.chentaoqian.com/?p=569</guid>
		<description><![CDATA[Mysql主从同步延迟受到多种因素影响， 比如大事务， 从库查询压力， 网路延迟等； 这些比较常见； 但还受到主从机器系统时钟差的影响，这一点可能容易被忽视。
上周， 就遇到了这样的情况， 主库的系统时间由于某种原因落后于从库几十秒， 结果频繁的出现大的主从延迟同步 ，查了N久业务方面的问题， 都找不出原因； 在和同事的交流中，发现大家对参数Seconds_Behind_Master的理解有点补一样，基本有两种理解：
一种理解是来源于Mysql手册上的描述， 大体意思是这个时间是从库SQL线程处理的最近的日志事件的时间戳减去从库IO线程处理的最近一条日志记录的时间戳得到的, 可以简单理解为从库SQL线程与IO线程所处理的最近的日志事件的时间戳差；这个计算方式给人的感觉不是在计算主从延迟，而是在计算从库上两个线程的处理 的日志的时差。
另一种理解来源于《High Performace Mysql》上的的描述， 大体意思这个参数反映的结果是当前系统时间减去从库IO线程所处理的最近一条日志记录的时间戳； 但这个说法有一个明显的不太让人信服的地方， 就是如果机器的系统时间相差比较大怎么办？ 显然， 如果系统时间相差比较大的话， 以这样的方式计算主从延迟毫无意义。
在有分歧的情况下， 去查看了一下Mysql的源代码， 结果发现手册上的描述居然不那么准确， 代码大致如下：
&#8230;&#8230;
if ((mi-&#62;slave_running == MYSQL_SLAVE_RUN_CONNECT) &#38;&#38;
mi-&#62;rli.slave_running)
{
long time_diff= ((long)(time(0) &#8211; mi-&#62;rli.last_master_timestamp)
- mi-&#62;clock_diff_with_master);
protocol-&#62;store((longlong)(mi-&#62;rli.last_master_timestamp ?
max(0, time_diff) : 0));
&#8230;&#8230;
}
else
{
protocol-&#62;store_null();
}
从代码看， 如果从库IO线程到主库的连接有问题或者SQL线程没有在运行， Seconds_Behind_Master直接返回NULL; 否则的话， 用从库当前系统时间减去IO线程处理的最近的事件的时间戳； 代码里用mi-&#62;clock_diff_with_master来排除系统时间差对计算的影响， 那这个值又是怎么计算来的呢？ 继续看代码：
&#8230;&#8230;
if (!mysql_real_query(mysql, STRING_WITH_LEN(&#8220;SELECT UNIX_TIMESTAMP()&#8221;)) &#38;&#38;
(master_res= mysql_store_result(mysql)) &#38;&#38;
(master_row= mysql_fetch_row(master_res)))
{
mi-&#62;clock_diff_with_master =  [...]]]></description>
		<wfw:commentRss>http://www.chentaoqian.com/archives/569/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL表设计优化与索引 (十)</title>
		<link>http://www.chentaoqian.com/archives/566</link>
		<comments>http://www.chentaoqian.com/archives/566#comments</comments>
		<pubDate>Wed, 28 Apr 2010 15:06:42 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[优化]]></category>
		<category><![CDATA[数据库]]></category>

		<guid isPermaLink="false">http://www.chentaoqian.com/?p=566</guid>
		<description><![CDATA[Bit-Packed Data Types
MySQL有一些存储类型使用一个值中的一些单个的比特位来紧凑的存储数据。纯技术上将，不管是底层的存储格式还是操作，所有这些类型都是字符串类型。
BIT
MySQL5.0以前， BIT只是TINYINT的同义词而已。但是在MySQL5.0以及之后的版本，BIT是一个完全不同的数据类型了， 有着自己的一些特点， 这里讨论一些新的行为和属性:
可以用BIT字段在单列里面来存储一个或多个true/false值， BIT(1)定义一个了只包含单个比特位的字段， BIT(2)是存储2个比特位的字段， 如此类推；BIT字段的最大长度可以是64个比特。
BIT类型的行为与存储引擎有关。MyISAM把一些列为了存储的目的打包到一起， 所以17个单独的BIT列需要17个比特来存储(假定这些列都不允许NULL)，MyISAM会近似算成3个字节来存储。其他的一些存储引擎， 比如Memory和InnoDB, 把每个列都用有足够长度存储这些比特位的最小整数来存储，所以无法节省存储空间。
* TIMESTAMP类型的一些行为的规则比较复杂并随着不同的MySQL版本而变化，所以在使用时应当确认是自己所期望的行为。通常， 在对TIMESTAMP的列做了改变后通过查看SHOW CREATE TABALE的结果来确认是一个的主意。
MySQL把BIT当做字符串类型， 而不是数据类型。当检索BIT(1)列的值， 结果是一个字符串而内容是二进制位0或1， 而不是ASCII值&#8221;0&#8243;或&#8221;1&#8243;.然而， 如果在一个数值上下文检索的话， 结果是比特串转化而成的数字。 当需要与另一个值进行比较时， 记住这一点。比如， 如果存储值&#8217;00111001&#8242;（是57的二进制表示）到一个BIT(8)的字段中然后检索出来，得到的是字符编码值为57字符串， 而这值就是“9”的ASCII编码。但是在数值环境中， 得到的是值57:s
mysql&#62; CREATE TABLE bittest(a bit(8));
mysql&#62; INSERT INTO bittest VALUES(b&#8217;00111001&#8242;);
mysql&#62; SELECT a, a + 0 FROM bittest;
+&#8212;&#8212;+&#8212;&#8212;-+
&#124; a &#124; a + 0 &#124;
+&#8212;&#8212;+&#8212;&#8212;-+
&#124; 9 &#124; 57 &#124;
+&#8212;&#8212;+&#8212;&#8212;-+
这非常容易引起混淆， 所以我们提醒小心使用BIT类型。对于大多数应用程序来说，避免使用这个类型比较的好。
如果想在单个比特位的存储空间中存储true/false值的另一个选择是使用可以为NULL的CHAR(0)列。这个列能够存储NULL和长度为0的空串。
SET
如果需要存储多个true/false的值， 可以考虑把多个列放到一个MySQL所支持的SET数据类型，而MySQL内部通过一些比特位来表示的。这种类型有效的使用存储空间， MySQL也有一些函数如FIND_IN_SET( )和FIELD( [...]]]></description>
		<wfw:commentRss>http://www.chentaoqian.com/archives/566/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL表设计优化与索引 (九)</title>
		<link>http://www.chentaoqian.com/archives/564</link>
		<comments>http://www.chentaoqian.com/archives/564#comments</comments>
		<pubDate>Tue, 27 Apr 2010 14:58:55 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[优化]]></category>
		<category><![CDATA[数据库]]></category>

		<guid isPermaLink="false">http://www.chentaoqian.com/?p=564</guid>
		<description><![CDATA[日期和时间类型
MySQL有多个表示各种日期和时间值的数据类型， 比如YEAR和DATE. MySQL存储时间的最精确粒度是秒。 然而， 能做微妙粒度的临时计算， 我们会列出一些绕过存储引擎限制的一些方法。
许多时间类型都没有可替换类型， 因而不存在什么是最佳选择这么一说。 唯一的问题是当需要一起存储日期和时间时如何做？MySQL提供了两个非常类似的数据类型来做这个事情: DATETIME和TIMESTAMP. 多大多数应用来说， 两个都行， 但是在某些场合， 一个可能比另一个更合适：
DATETIME
这个类型能够存储很大范围的值， 从1001年到9999年， 准确到秒的精度。它把日期和时间打包成整数以YYYYMMDDHHMMSS 格式表示， 与时区无关。用8个字节的存储空间。
缺省情况下， MySQL以可排序，无歧义的格式显示DATETIME值， 比如 2008-01-16 22:37:08, 这是ANSI下标准显示日期时间的方式。
TIMESTAMP
如名字所指出的，TIMESTAMP 类型存储从1970年1月1日(格林威治时间)到目前为止经过的秒数 &#8211;与UNIX时间戳一样。TIMESTAMP 使用4个字节来存储值， 所能表示的范围以比DATETIME要小: 从1970年到2038年。MySQL提供了 FROM_UNIXTIME( ) 和 UNIX_TIMESTAMP( ) 两个函数来进行Unix时间戳与日期类型的相互转换。
新版本的MySQL中TIMESTAMP 采用了与DATETIME 一样的格式来表示值，但是老版本的MySQL没有在各个部分件显示分隔符。 这只是一个显示格式的区别而已，TIMESTAMP 的存储格式在各个版本与DATETIME一致。
TIMESTAMP 对值的显示与时区相关，MySQL服务器，操作系统和客户端连接都有相应的时区设置。
因此，对于与GMT有5个小时时差的东部时间，一个值为0的TIMESTAMP 类型实际显示的内容可能会是1969-12-31 19:00:00。
TIMESTAMP 也有一些DATETIME所不具备的一些属性。 缺省情况下， 插入记录时，MySQL会把第一个没指定具体值得TIMESTAMP 类型的字段自动设置为当前值，在修改时， 如果没有在修改语句中显式的指定值， 第一个DATESTAMP类型的字段的值也会被更行为当前值。也可以通过配置修改修改和插入记录时对TIMESTAMP 列的处理行为。最后， TIMESTAMP列缺省不为NULL, 这与其他数据类型不一样。
除了一些特殊行为，在一般情况下，如果能够使用TIMESTAMP，就使用它， 因为它比DATETIME的空间效率要高。有时候，有人把Unix时间戳存储成整数， 但是实际上没有任何好处，因为格式转换很不方便，我们不推荐这么做。
如果需要存储比秒精度更高的日期和时间数据怎么办呢？MySQL当前并没有提供合适的数据类型， 但是可以根据需要选择自己的存储格式：可以使用BIGINT类型存储毫秒精度的数据，或者使用DOUBLE类型，把秒后面的数值当做小数点后面的小数部分。 这两种方法都不错。
]]></description>
		<wfw:commentRss>http://www.chentaoqian.com/archives/564/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MySQL表设计优化与索引 (八)</title>
		<link>http://www.chentaoqian.com/archives/561</link>
		<comments>http://www.chentaoqian.com/archives/561#comments</comments>
		<pubDate>Mon, 26 Apr 2010 12:17:44 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[优化]]></category>
		<category><![CDATA[数据库]]></category>

		<guid isPermaLink="false">http://www.chentaoqian.com/?p=561</guid>
		<description><![CDATA[使用ENUM代替字符串类型
有时候， 可以通过使用ENUM来代理常规的字符串类型。一个ENUM列能够存储65535个不同的字符串值，MySQL非常紧凑的存储这些值，会根据值列表把这些值存储到1到2个字节中。通过在表的.frm文件中保存一个数字到字符串的对应关系来保存一个&#8221;查询表&#8221;， 它把每个值存储成一个表示值在字段定义列表中的某个位置的整数。 下面是几个例子;
mysql&#62; CREATE TABLE enum_test(
-&#62; e ENUM(&#8216;fish&#8217;, &#8216;apple&#8217;, &#8216;dog&#8217;) NOT NULL
-&#62; );
mysql&#62; INSERT INTO enum_test(e) VALUES(&#8216;fish&#8217;), (&#8216;dog&#8217;), (&#8216;apple&#8217;);
这3列实际上存储的是整数， 而不是字符串。 能够通过在数字检索上下文中查看到这些值的两面属性：
mysql&#62; SELECT e + 0 FROM enum_test;
+&#8212;&#8212;-+
&#124; e + 0 &#124;
+&#8212;&#8212;-+
&#124; 1 &#124;
&#124; 3 &#124;
&#124; 2 &#124;
+&#8212;&#8212;-+
如果指定数字当做ENUM常量的话， 这个两面性太容易引起混淆了。建议不要这么做。
另外一个令人奇怪的是ENUM字段通过整数值来排序， 而不是字符串本省：
mysql&#62; SELECT e FROM enum_test ORDER BY e;
+&#8212;&#8212;-+
&#124; e &#124;
+&#8212;&#8212;-+
&#124; fish &#124;
&#124; apple &#124;
&#124; dog &#124;
+&#8212;&#8212;-+
通过指定期望的ENUM数字的排序顺序来解决这个问题。也可以通过在查询中显式的使用FIELD()来指定排序顺序， [...]]]></description>
		<wfw:commentRss>http://www.chentaoqian.com/archives/561/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

