从开始使用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 … FROM t_mytable WHERE F_pid=’val’ AND F_time_1>= ‘time1′ AND F_TIME_1 <= ‘time2′ ORDER BY F_time_1, 记录条目是12条, 但发现效率很低;觉得很奇怪:这个语句的效率应该高才对的
2. 尝试着改了一下sql语句为SELECT … FROM t_mytable WHERE F_pid=’val’ AND F_time_2>= ‘time1′ AND F_TIME_2 <= ‘time2′ ORDER BY F_time_1,记录条目是8条,效率很高;
阅读全文…
相关日志
第一部分, innodb的线程模型:
innodb内部大体上有三类线程, 主线程(只有一个); 用户线程 , 用户线程根据不同的职责也可以分成两类; 辅助线程
整个innodb由一个主线程控制, 这个线程是innodb一起来的时候就开始运行(入口函数是srv_master_thread), 它的优先级相对于其他innodb内部的线程来说优先级较高, 大部分时间下, 这个线程处于sleep状态, 每隔一定间隔这个线程起来看看是否有什么任务需要处理,这些任务包括:
1. drop延迟删除的表(如果有的话)
阅读全文…
相关日志
页面读入机制
当读入页面的时候, 首先需要找到一个可用的block, 这个block或者来自于free list或者lru-list; 在读入数据块的时候, block会加上排他锁以防止其他线程再次使用这个block,
会在block中标记出这个块正处于io状态, 然后把io请求加入到io调用请求对列; 完成读入操作时, 再释放block上的拍它锁更新io状态。
数据页面的读取写入
缓冲池中的数据基本是采用同步aio的方式,这里的同步aio的意思是: 工作线程发出读或写请求后,请求会被放到一个读写请求队列中,由专门的io线程负责写盘和读盘,而工作线程则等待io的完成,
阅读全文…
相关日志
在数据库数据处理中, 缓冲在改善性能方面扮演着很重要的角色, 为了保证性能, 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上存的是需要保存到磁盘上的数据, 这些数据可能是数据记录信息, 也可以是索引信息或其他的元数据等;
阅读全文…
相关日志
innodb的同步管理
数据库是支持多客户端同时连接和处理的, 因此多线程是必然的,多线程编码很重要的一个方面是处理同步和互斥,innodb的互斥机制有两个:mutex和rw-lock; 当某个线程需要获取一个mutex或rw-lock时,有两种结果可能发生, 一是直接获得了mutex从而继续处理;一个是无法获得mutex只得等待拥有线程释放mutex. 多线程编码技术中, 是通过信号量来通知等待线程mutex的可用性的, mysql在处理时并没有直接使用操作系统提供的信号量机制, 而是实现了自己的信号量机制,之所以不用操作系统的信号量机制而自己实现的主要原因是操作系统的信号量机制比较慢,其次一个原因是(某些)操作系统的信号量处理往往导致线程切换,而在很多时候, 有比不做线程切换更高效的事情:在多处理器系统上,通过循环等待旋转锁(spin lock), 当然, 在只有单处理器的系统上,循环等待明显是低效的事情。再一个原因是, 便于分析同步情况, 从而避免死锁, 因为当所有的同步信息交给操作系统处理时, 就难以分析死锁情况了,如果有自己的数据结构来管理这些信息, 死锁情况就容易分析。
阅读全文…
相关日志
在查mysql的排序问题时, 了解了一下Mysql的排序机制, 大体是:
mysql把需要排序的地方都叫filesort, 名字上看有个file在里面,但不一定与文件有关, 可能就是在内存完成的排序。
MySQL 有二个 filesort 算法, 第一个方法(原始方法)只使用了ORDER BY中指定的字段。第二个方法(改进的方法)不仅使用ORDER BY中指定的字段,还是用了查询中所涉及到的所有的字段。
优化器决定选择哪个filesort 算法, 除了查询中涉及到TEXT或者BLOCk字段外,它通常使用改进的算法,当查询中涉及到TEXT或者BLOCk字段时,通常使用原始的方法。
原始的 filesort 算法的工作机制大体是(典型的外排算法):
阅读全文…
相关日志
Mysql主从同步延迟受到多种因素影响, 比如大事务, 从库查询压力, 网路延迟等; 这些比较常见; 但还受到主从机器系统时钟差的影响,这一点可能容易被忽视。
上周, 就遇到了这样的情况, 主库的系统时间由于某种原因落后于从库几十秒, 结果频繁的出现大的主从延迟同步 ,查了N久业务方面的问题, 都找不出原因; 在和同事的交流中,发现大家对参数Seconds_Behind_Master的理解有点补一样,基本有两种理解:
一种理解是来源于Mysql手册上的描述, 大体意思是这个时间是从库SQL线程处理的最近的日志事件的时间戳减去从库IO线程处理的最近一条日志记录的时间戳得到的, 可以简单理解为从库SQL线程与IO线程所处理的最近的日志事件的时间戳差;这个计算方式给人的感觉不是在计算主从延迟,而是在计算从库上两个线程的处理 的日志的时差。
阅读全文…
相关日志
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值”0″或”1″.然而, 如果在一个数值上下文检索的话, 结果是比特串转化而成的数字。 当需要与另一个值进行比较时, 记住这一点。比如, 如果存储值’00111001′(是57的二进制表示)到一个BIT(8)的字段中然后检索出来,得到的是字符编码值为57字符串, 而这值就是“9”的ASCII编码。但是在数值环境中, 得到的是值57:s
阅读全文…
相关日志
日期和时间类型
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日(格林威治时间)到目前为止经过的秒数 –与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类型,把秒后面的数值当做小数点后面的小数部分。 这两种方法都不错。
相关日志
使用ENUM代替字符串类型
有时候, 可以通过使用ENUM来代理常规的字符串类型。一个ENUM列能够存储65535个不同的字符串值,MySQL非常紧凑的存储这些值,会根据值列表把这些值存储到1到2个字节中。通过在表的.frm文件中保存一个数字到字符串的对应关系来保存一个”查询表”, 它把每个值存储成一个表示值在字段定义列表中的某个位置的整数。 下面是几个例子;
mysql> CREATE TABLE enum_test(
-> e ENUM(‘fish’, ‘apple’, ‘dog’) NOT NULL
-> );
mysql> INSERT INTO enum_test(e) VALUES(‘fish’), (‘dog’), (‘apple’);
这3列实际上存储的是整数, 而不是字符串。 能够通过在数字检索上下文中查看到这些值的两面属性:
阅读全文…
相关日志
如何避免磁盘临时表
因为内存储引擎不支持TEXT和BLOB数据类型, 使用到BLOB和TEXT列的查询和使用隐式临时表的查询将不得不使用MyISAM的磁盘临时表, 即使只有很少的几条记录。 这可能导致很严重的性能开销。即使把MySQL配置成在RAM盘上使用临时表, 也会用到一些开销大的系统调用(Maria存储引擎应该能通过把所有的东西, 而不只是索引,缓存在内存中而在一定程度上缓解这个问题)。最好的解决办法是避免使用BLOB和TEXT类型, 除非费用不可。
.
如果无法避免使用BLOB和TEXT类型, 应该能够通过使用ORDER BY SUBSTRING(column, length)
的办法来把这些类型的值转化成字符串,这样不会妨碍使用内存临时表。另外, 确认一下的所使用的子串的长度是否短到不会导致临时表的大小不会超过 max_heap_table_size 或 tmp_table_size, 否则,还是会生成MyISAM的磁盘临时表。
如果EXPLAIN结果中的”Extra”列里面包含”Using temporary”, 那么查询会使用一个隐式的临时表。
相关日志
BINARY和VARBINARY
数据的存储是存储引擎相关的, 并不是所有的存储引擎用同样的方式来处理定长和变长类型。Memory存储引擎使用定长的行, 因而它分配尽可能多的空间给变长字段来存储数据。 而Falcon则使用变长字段来存储, 即使对于CHAR字段也是如此。 但是填充和去尾是一致de 这是因为这个是由MySql服务器自己处理的。
CHAR和VCHAR的兄弟类型分别是存储二进制数据的BINARY和VARBINARY, 二进制字符串与普通的字符长相似, 不过他们是以字节存储的, 而不是字符,填充也不一样 , Mysql用\0(0 字节)而不是空格填充二进制数据, 而在检索时不会把后面的填充值去掉。
对于需要存数二进制数据的活着需要Mysql对值进行字节的比较而不是基于字符的比较时, 二进制数据类型非常有用。基于字节的比较的优势不只是大小写不敏感的好处, Mysql在比较二进制数据时, 通过字节表示的数值比较的方式进行的, 因为二进制数据相对与基于字符的比较更简单, 也更快。
相关日志