提高数据库使用时的性能

在一个WEB项目的各个因素当中,那个是影响速度的关键?
当然是数据,而数据库又是数据存储的载体,每次对数据库进行的操作,SQL语句的精简与否对效率是有很大的影响的。
今天在CuPHP版瞎逛的时候,看到有人在问关于一个项目中要设计一个会员在同一时间只能在一个地方登录的功能。他的本意是用数据库来解决,但是考虑到每次都要操作数据库,效率上可能跟不上,于是提出用缓存的方式来解决。但是版主回复说“ 数据表的类型有MEMORY(HEAP)模式,速度很快的。很多程序,例如论坛就这么做。”
立马连上服务器上mysql,但是死活找不到这个类型的数据类型。于是上GOOGLE搜索了一番,发现的确有这个么一个类型的字段,看字面的意思就是内存级别的数据-_×,手册上的解释是:

15.4. MEMORY (HEAP)存储引擎
MEMORY存储引擎用存在内存中的内容来创建表。这些在以前被认识为HEAP表。MEMORY是一个首选的术语,虽然为向下兼容,HEAP依旧被支持。 

每个MEMORY表和一个磁盘文件关联起来。文件名由表的名字开始,并且由一个.frm的扩展名来指明它存储的表定义。 

要明确指出你想要一个MEMORY表,可使用ENGINE选项来指定: 

CREATE TABLE t (i INT) ENGINE = MEMORY;如它们名字所指明的,MEMORY表被存储在内存中,且默认使用哈希索引。这使得它们非常快,并且对创建临时表非常有用。可是,当服务器关闭之时,所有存储在MEMORY表里的数据被丢失。因为表的定义被存在磁盘上的.frm文件中,所以表自身继续存在,在服务器重启动时它们是空的。 

这个例子显示你如何可以创建,使用并删除一个MEMORY表: 

mysql> CREATE TABLE test ENGINE=MEMORY    
    ->     SELECT ip,SUM(downloads) AS down    
    ->     FROM log_table GROUP BY ip;
mysql> SELECT COUNT(ip),AVG(down) FROM test;
mysql> DROP TABLE test;
MEMORY表有下列特征: 

·         给MEMORY表的空间被以小块来分配。表对插入使用100%动态哈希来。不需要溢出区或额外键空间。自由列表无额外的空间需求。已删除的行被放在一个以链接的列表里,并且在你往表里插入新数据之时被重新使用。MEMORY表也没有通常与在哈希表中删除加插入相关的问题。 

·         MEMORY表可以有多达每个表32个索引,每个索引16列,以及500字节的最大键长度。 

·         MEMORY存储引擎执行HASH和BTREE索引。你可以通过添加一个如下所示的USING子句为给定的索引指定一个或另一个: 

·                CREATE TABLE lookup
·                    (id INT, INDEX USING HASH (id))
·                    ENGINE = MEMORY;
·                CREATE TABLE lookup
·                    (id INT, INDEX USING BTREE (id))
·                    ENGINE = MEMORY;
B树的一般特征和哈希索引在7.4.5节,“MySQL如何使用索引”里描述。 

·         你可以在一个MEMORY表中有非唯一键。(对哈希索引的实现,这是一个不常用的功能)。 

·         你页可以对MEMORY表使用INSERT DELAYED。请参阅13.2.4.2节,“INSERT DELAYED语法” 

·         如果你在一个有高度键重复的(许多索引条目包含同一个值)MEMORY表上有一个哈希索引,对影响键值的表的更新及所有删除都是明显地慢的。这个变慢的程度比例于重复的程度(或者反比于索引cardinality)。你可以使用一个B树索引来避免这个问题。 

·         MEMORY表使用一个固定的记录长度格式。 

·         MEMORY不支持BLOB或TEXT列。 

·         MEMORY支持AUTO_INCREMENT列和对可包含NULL值的列的索引。 

·         MEMORY表在所有客户端之间共享(就像其它任何非TEMPORARY表)。 

·         MEMORY表内容被存在内存中,内存是MEMORY表和服务器在查询处理之时的空闲中创建的内部表共享。可是,两个类型的表不同在于MEMORY表不会遇到存储转换,而内部表是: 

-        如果一个内部表变得太大,服务器自动把它转换为一个磁盘表。尺寸限制由tmp_table_size系统变量的值来确定。 

-        MEMORY表决不会转换成磁盘表。要确保你不会偶尔做点傻事,你可以设置max_heap_table_size系统变量给MEMORY表加以最大尺寸。对于单个的表,你也可以在CREATE TABLE语句中指定一个MAX_ROWS表选项。 

·         服务器需要足够内存来维持所有在同一时间使用的MEMORY表。 

·         当你不再需要MEMORY表的内容之时,要释放被MEMORY表使用的内存,你应该执行DELETE FROM或TRUNCATE TABLE,或者整个地删除表(使用DROP TABLE)。 

·         当MySQL服务器启动时,如果你想开拓MEMORY表,你可以使用--init-file选项。例如,你可以把INSERT INTO ... SELECT 或LOAD DATA INFILE这样的语句放入这个文件中以便从持久稳固的的数据源装载表。请参阅5.3.1节,“mysqld 命令行选项” and 13.2.5节,“LOAD DATA INFILE 语法”。 

·         如果你正使用复制,当主服务器被关闭且重启动之时,主服务器的MEMORY表变空。可是从服务器意识不到这些表已经变空,所以如果你从它们选择数据,它就返回过时的内容。自从服务器启动后,当一个MEMORY表在主服务器上第一次被使用之时,一个DELETE FROM语句被自动写进主服务器的二进制日志,因此再次让从服务器与主服务器同步。注意,即使使用这个策略,在主服务器的重启和它第一次使用该表之间的间隔中,从服务器仍旧在表中有过时数据。可是,如果你使用--init-file选项于主服务器启动之时在其上推行MEMORY表。它确保这个时间间隔为零。 

·         在MEMORY表中,一行需要的内存使用下列表达式来计算: 

·                SUM_OVER_ALL_BTREE_KEYS(max_length_of_key + sizeof(char*) * 4)·                + SUM_OVER_ALL_HASH_KEYS(sizeof(char*) * 2)·                + ALIGN(length_of_row+1, sizeof(char*))ALIGN()代表round-up因子,它使得行的长度为char指针大小的确切倍数。sizeof(char*)在32位机器上是4,在64位机器上是8。 

对于MEMORY存储引擎,在http://forums.mysql.com/list.php?92上有一个专门的论坛。 

可见他的速度是相当快的,完全可以胜任这个功能!
不过。MYSQL的版本要高一点点(国内虚拟主机的版本应该都支持这个了!)

在找资料的同时,看到一个站点上翻译的关于MYSQL的文章,还不错,尤其是对mysql进行优化的地方,简单总结几点:
在设计数据表的时候,尽可能使用最有效(最小的)数据类型,尽可能使用更小的整数类型,可能定义字段类型为 NOT NULL。这会运行的更快,而且每个字段都会节省1个bit。如果在应用程序中确实需要用到 NULL,那么就明确的指定它。不过要避免所有的字段默认值是 NULL),尽可能使用最有效(最小的)数据类型。MySQL有好几种特定的类型能节省磁盘和内存。 尽可能使用更小的整数类型。在 MyISAM 表中,如果没有用到任何变长字段(VARCHAR, TEXT, 或 BLOB字段)的话,那么就采用固定大小的记录格式。这样速度更快,不过可能会浪费点空间。表的主索引应尽可能短。这样的话会每条记录都有名字标识且更高效。 只创建确实需要的索引。索引有利于检索记录,但是不利于快速保存记录。如果总是要在表的组合字段上做搜索,那么就在这些字段上创建索引。索引的第一部分必须是最常使用的字段.如果总是需要用到很多字段,首先就应该多复制这些字段,使索引更好的压缩。 一个字段很有可能在最开始的一些数量字符是各不相同的,因此在这些字符上做索引更合适。MySQL支持在一个字段的最左部分字符做索引。索引越短,速度越快,不仅是因为它占用更少的磁盘空间,也因为这提高了索引缓存的命中率,由此减少了磁盘搜索。在某些情况下,把一个频繁扫描的表分割成两个更有利。在对动态格式表扫描以取得相关记录时,它可能使用更小的静态格式表的情况下更是如此。

进行数据库操作的时候,能有多简单就有多简单,能不用圆括号就不用圆括号,去掉那些多余的选项,能用SQL解决的就不要用程序语言来处理(mysql处理的速度比解析语言快很多);

删除表中所有数据的时候,用效率更高的TRUNCATE TABLE tbl_name 而不是DELETE FROM tbl_name;

在锁表的情况下,更新多个记录比多次更新记录要快很多,因此:推迟更新并且把很多次更新放在后面一起做。

数据库在连接时的开销很大,一个页面行不要有多次对库进行连接和关闭的操作!

在同时用 limited count和order by 的时候,找到count 记录之后,就停止扫描数据表里,因此,排序只有在所搜索的数据部分进行排序,并不是整个数据表(特别要注意!)

经常需要读写操作的表用 MEMORY(HEAP)表!

先整理这么多,具体的信息您可以查看MYSQL文档或者直接上官方中文版

关于删除这块,access和MSSQL也适用!

    我来说几句: