PHP程序员站--PHP编程开发平台
 当前位置:主页 >> 数据库 >> MySQL >> 

MySQL优化之数据表的处理

MySQL优化之数据表的处理

来源:互联网  作者:  发布时间:2008-12-12
摘要:本文介绍了有关数据表的优化技巧,主要内容有,选择表的

能用myisamchk解压缩。

MySQL能支持不同的索引类型,但是一般的类型是ISAM。这是一个B树索引并且你能粗略地为索引文件计算大小为(key_length+4)*0.67,在所有的键上的总和。(这是对最坏情况,当所有键以排序顺序被插入时。)

字符串索引是空白压缩的。如果第一个索引部分是一个字符串,它也将压缩前缀。如果字符串列有很多尾部空白或是一个总不能用到全长的VARCHAR列,空白压缩使索引文件更小。如果很多字符串有相同的前缀,前缀压缩是有帮助的。

MySQL内存表的特点

堆表仅存在于内存中,因此如果mysqld被关掉或崩溃,它们将丢失,但是因为它们是很快,不管怎样它们是有用的。

MySQL内部的HEAP表使用没有溢出区的100%动态哈希并且没有与删除有关的问题。

你只能通过使用在堆表中的一个索引的用等式存取东西(通常用=操作符)。

堆表的缺点是:

·你要为你想要同时使用的所有堆表需要足够的额外内存。

·你不能在索引的一个部分上搜索。

·你不能顺序搜索下一个条目(即使用这个索引做一个ORDER BY)。

·MySQL也不能算出在2个值之间大概有多少行。这被优化器使用来决定使用哪个索引,但是在另一方面甚至不需要磁盘寻道。

数据库表的数量的问题

在同一个数据库中创建大量数据库表的缺点是,如果你在一个目录中有许多文件,打开、关闭和创建操作将会很慢。如果你执行在许多不同表上的 SELECT语句,当表缓存满时,将有一点开销,因为对每个必须打开的表,另外一个必须被关闭。你可以通过使表缓冲更大些来减少这个开销。

为什么有这么多打开的表?

当你运行mysqladmin status时,你将看见象这样的一些东西:

Uptime: 426 Running threads: 1 Questions: 11082 Reloads: 1 Open tables: 12

如果你仅有6个表,这可能有点令人困惑。

MySQL是多线程的,因此它可以同时在同一个表上有许多询问。为了是2个线程在同一个文件上有不同状态的问题减到最小,表由每个并发进程独立地打开。这为数据文件消耗一些内存和一个额外的文件描述符。索引文件描述符在所有线程之间共享。

数据库表级锁定的问题

前面的内容主要将精力集中在使个别的查询更快上。MySQL 还允许影响语句的调度特性,这样会使来自几个客户机的查询更好地协作,从而单个客户机不会被锁定太长的时间。更改调度特性还能保证特定的查询处理得更快。我们先来看一下 MySQL 的缺省调度策略,然后来看看为改变这个策略可使用什么样的选项。出于讨论的目的,假设执行检索(SELECT)的客户机程序为读取程序。执行修改表操作(DELETE,INSERT,REPLACE 或 UPDATE)的另一个客户机程序为写入程序。

MySQL 的基本调度策略可总结如下:

·写入请求应按其到达的次序进行处理。

·写入具有比读取更高的优先权。

1、对此一个主要的问题如下:

·一个客户发出一个花很长时间运行的SELECT。

·然后其他客户在一个使用的表上发出一个UPDATE;这个客户将等待直到SELECT完成。

·另一个客户在同一个表上发出另一个SELECT语句;因为UPDATE比SELECT有更高的优先级,该SELECT将等待UPDATE的完成。它也将等待第一个SELECT完成!

对这个问题的一些可能的解决方案是:

·试着使SELECT语句运行得更快;你可能必须创建一些摘要(summary)表做到这点。

·用--low-priority-updates启动mysqld。这将给所有更新(修改)一个表的语句以比SELECT语句低的优先级。在这种情况下,在先前情形的最后的SELECT语句将在INSERT语句前执行。

·你可以用LOW_PRIORITY属性给与一个特定的INSERT、UPDATE或DELETE语句较低优先级。

·为max_write_lock_count指定一个低值来启动mysqld使得在一定数量的WRITE锁定后给出READ锁定。

·通过使用SQL命令:SET SQL_LOW_PRIORITY_UPDATES=1,你可从一个特定线程指定所有的更改应该由用低优先级完成。见SET OPTION句法。

·你可以用HIGH_PRIORITY属性指明一个特定SELECT是很重要的。见SELECT句法。

·如果你有关于INSERT结合SELECT的问题,切换到使用新的MyISAM表,因为它们支持并发的SELECT和INSERT。

·如果你主要混合INSERT和SELECT语句,DELAYED属性的INSERT将可能解决你的问题。INSERT句法。

·如果你有关于SELECT和DELETE的问题,LIMIT选项的DELETE可以帮助你。见DELETE句法。

2、INSERT DELAYED 在客户机方的作用

如果其他客户机可能执行冗长的 SELECT 语句,而且您不希望等待插入完成,此时 INSERT DELAYED 很有用。发布 INSERT DELAYED 的客户机可以更快地继续执行,因为服务器只是简单地将要插入的行插入。

不过应该对正常的 INSERT 和 INSERT DELAYED 性能之间的差异有所认识。如果 INSERT DELAYED 存在语法错误,则向客户机发出一个错误,如果正常,便不发出信息。例如,在此语句返回时,不能相信所取得的 AUTO_INCREMENT 值。也得不到惟一索引上的重复数目的计数。之所以这样是因为此插入操作在实际的插入完成前返回了一个状态。其他还表示,如果 INSERT DELAYED 语句的行在等待插入中被排队,并且服务器崩溃或被终止(用 kill -9),那么这些行将丢失。正常的 TERM 终止不会这样,服务器会在退出前将这些行插入。

在表锁的帮助下实现调度策略。客户机程序无论何时要访问表,都必须首先获得该表的锁。可以直接用 LOCK TABLES 来完成这项工作,但一般服务器的锁管理器会在需要时自动获得锁。在客户机结束对表的处理时,可释放表上的锁。直接获得的锁可用 UNLOCK TABLES 释放,但服务器也会自动释放它所获得的锁。

执行写操作的客户机必须对表具有独占访问的锁。在写操作进行中,由于正在对表进行数据记录的删除、增加或更改,所以该表处于不一致状态,而且该表上的索引也可能需要作相应的更新。如果表处于不断变化中,此时允许其他客户机访问该表会出问题。让两个客户机同时写同一个表显然不好,因为这样会很快使该表不可用。允许客户机读不断变化的表也不是件好事,因为可能在读该表的那一刻正好正在对它进行更改,其结果是不正确的。

执行读取操作的客户机必须有一把防止其他客户机写该表的锁,以保证读表的过程中表不出现变化。不过,该锁无需对读取操作提供独占访问。此锁还允许其他客户机同时对表进行读取。读取不会更改表,所有没必要阻止其它客户机对该表进行读取。

MySQL 允许借助几个查询限修饰符对其调度策略施加影响。其中之一是 DELETE、INSERT、LOAD DATA、REPLACE 和 UPDATE 语句的 LOW_PRIORITY 关键字。另一个是 SELECT 语句的 HIGH_PRIORITY 关键字。第三个是 INSERT 和 REPLACE 语句的 DELAYED 关键字。

LOW_PRIORITY 关键字按如下影响调度。一般情况下,如果某个表的写入操作在表正被读取时到达,写入程序被阻塞,直到读取程序完成,因为一旦某个查询开始,就不能中断。如果另一读取请求在写入程序等待时到达,此读取程序也被阻塞,因为缺省的调度策略为写入程序具有比读取程序高的优先级。在第一个读取程序结束时,写入程序继续,在此写入程序结束时,第二个读取程序开始。

如果写入请求为 LOW_PRIORITY 的请求,则不将该写入操作视为具有比读取操作优先级高的操作。在此情形下,如果第二个读取请求在写入程序等待时到达,则让第二个读取操作排在等待的写入操作之前。仅当没有其他读取请求时,才允许写入程序执行。这种调度的更改从理论上说,其含义为 LOW_PRIORITY 写入可能会永远被阻塞。当正在处理前面的读取请求时,只要另一个读取请求到达,这个新的请求允许排在 LOW_PRIORITY 写入之前。

SELECT 查询的 HIGH_PRIORITY 关键字作用类似。它使 SELECT 插在正在等待的写入操作之前,即使该写入操作具有正常的优先级。

INSERT 的 DELAYED 修饰符作用如下,在表的一个 INSERT DELAYED 请求到达时,服务器将相应的行放入一个队列,并立即返回一个状态到客户机程序,以便该客户机程序可以继续执行,即使这些行尚未插入表中。如果读取程序正在对表进行读取,那么队列中的行挂起。在没有读取时,服务器开始开始插入延迟行队列中的行。服务器不时地停下来看看是否有新的读取请求到达,并进行等待。如果是这样,延迟行队列将挂起,并允许读取程序继续。在没有其他的读取操作时,服务器再次开始插入延迟行。这个过程一直进行到延迟行队列空为止。

此调度修饰符并非出现在所有 MySQL 版本中。下面的表列出了这些修饰符和支持这些修饰符的 MySQL 版本。可利用此表来判断所使用的 MySQL 版本具有什么样的功能:

语句类型 开始出现的版本

DELETE LOW_PRIOrITY3.22.5
INSERT LOW+PRIOrITY3.22.5
INSERT DELAYED3.22.15
LOAD DATA LOW_PRIORITY3.23.0
LOCK TABLES ... LOW_PRIORITY3.22.8
REPLACE LOW_PRIORITY3.22.5
REPLACE DELAYED3.22.15
SELECT ... HIGH_PRIORITY3.22.9
UPDATE LOW_PRIORITY3.22.5
SET SQL_LOW_PRIORITY_UPDATES3.22.5


对表进行优化

对表的长期使用,由于记录的删除与插入,会在表的数据文件产生碎片,下面的几种情况尤其会有产生碎片的效果:

·使用VARCHAR类型
频繁使用可变长列的结果就是使表非常容易产生碎片,如果空间允许,尽量采用定长类型CHAR。

·使用类型BLOB和TEXT
特别是进行大量的 DELETE 或 UPDATE 操作时更是如此。删除 BLOB 会在表中留下一个大空白,在以后将需用一个记录或可能是不同大小的多个记录来填充。

·删除了一个表的大部分,这同样会在表中留下大量空白。

为了消除表的碎片对性能的影响,需要对表进行优化。在第七章我们介绍了优化表的方法:

1、使用SQL语句OPTIMIZE

OPTIMIZE TABLE tbl_name

2、使用修复程序myisamchk或isamchk

 

Tags: mysql   优化   数据库   mysql优化   数据表   数据   优化   select   程序   insert   sql     sql优化  
最新文章
推荐阅读
月点击排行榜
PHP程序员站 Copyright © 2007-2010,PHPERZ.COM All Rights Reserved 粤ICP备07503606号