MySQL 性能优化(下)

1、INSERT语句的速度

插入一个记录需要的时间由下列因素组成,其中的数字表示大约比例:

连接:(3)、发送查询给服务器:(2)、分析查询:(2)、插入记录:(1x记录大小)、插入索引:(1x索引)、关闭:(1)。

这不考虑打开表的初始开销,每个并发运行的查询打开。表的大小以logN (B树)的速度减慢索引的插入。

加快插入的一些方法:

1)如果同时从同一个客户端插入很多行,使用含多个VALUE的INSERT语句同时插入几行。这比使用单行INSERT语句快(在某些情况下快几倍)。如果你正向一个非空表添加数据,可以bulk_insert_buffer_size变量,使数据插入更快。

2)如果你从不同的客户端插入很多行,能通过INSERT DELAYED语句加快速度。

3)用MyISAM,如果在表中没有删除的行,能在SELECT语句正在运行的同时插入行。

4)当从一个文本文件装载一个表时,使用LOAD DATA INFILE。这通常比使用很多INSERT语句快20倍。

5)当表有很多索引时,有可能要多做些工作使得LOAD DATA INFILE更快些。使用下列过程:

  • 有选择地用CREATE TABLE创建表。
  • 执行FLUSH TABLES语句或命令mysqladmin flush-tables。
  • 使用myisamchk --keys-used=0 -rq /path/to/db/tbl_name。这将从表中取消所有索引的使用。
  • 用LOAD DATA INFILE把数据插入到表中,因为不更新任何索引,因此很快。
  • 如果只想在以后读取表,使用myisampack压缩它。
  • 用myisamchk -r -q /path/to/db/tbl_name重新创建索引。这将在写入磁盘前在内存中创建索引树,并且它更快,因为避免了大量磁盘搜索。结果索引树也被完美地平衡。
  • 执行FLUSH TABLES语句或mysqladmin flush-tables命令。

请注意如果插入一个空MyISAM表,LOAD DATA INFILE也可以执行前面的优化;主要不同处是可以让myisamchk为创建索引分配更多的临时内存,比执行LOAD DATA INFILE语句时为服务器重新创建索引分配得要多。

也可以使用 ALTER TABLE tbl_name DISABLE KEYS 代替 myisamchk --keys-used=0 -rq /path/to/db/tbl_name,使用 ALTER TABLE tbl_name ENABLE KEYS 代替 myisamchk -r -q /path/to/db/tbl_name。使用这种方式,还可以跳过FLUSH TABLES。

6)锁定表可以加速用多个语句执行的INSERT操作:

LOCK TABLES a WRITE;
INSERT INTO a VALUES (1,23),(2,34),(4,33);
INSERT INTO a VALUES (8,26),(6,29);
UNLOCK TABLES;

这样性能会提高,因为索引缓存区仅在所有INSERT语句完成后刷新到磁盘上一次。一般有多少INSERT语句即有多少索引缓存区刷新。如果能用一个语句插入所有的行,就不需要锁定。

对于事务表,应使用BEGIN和COMMIT代替LOCK TABLES来加快插入。

锁定也将降低多连接测试的整体时间,尽管因为它们等候锁定最大等待时间将上升。例如:

Connection 1 does 1000 inserts
Connections 2, 3, and 4 do 1 insert
Connection 5 does 1000 inserts

如果不使用锁定,2、3和4将在1和5前完成。如果使用锁定,2、3和4将可能不在1或5前完成,但是整体时间应该快大约40%。

INSERT、UPDATE和DELETE操作在MySQL中是很快的,通过为在一行中多于大约5次连续不断地插入或更新的操作加锁,可以获得更好的整体性能。如果在一行中进行多次插入,可以执行LOCK TABLES,随后立即执行UNLOCK TABLES(大约每1000行)以允许其它的线程访问表。这也会获得好的性能。

INSERT装载数据比LOAD DATA INFILE要慢得多,即使是使用上述的策略。

7)为了对LOAD DATA INFILE和INSERT在MyISAM表得到更快的速度,通过增加key_buffer_size系统变量来扩大 键高速缓冲区。

2、UPDATE语句的速度

更新查询的优化同SELECT查询一样,需要额外的写开销。写速度依赖于更新的数据大小和更新的索引的数量。没有更改的索引不被更新。使更改更快的另一个方法是推迟更改然后在一行内进行多次更新。如果锁定表,同时做多个更新比一次做一个快得多。

请注意对使用动态记录格式的MyISAM表,更新一个较长总长的记录可能会切分记录。如果经常这样该,偶尔使用OPTIMIZE TABLE很重要。

3、DELETE语句的速度

删除一个记录的时间与索引数量确切成正比。为了更快速地删除记录,可以增加键高速缓冲的大小。如果想要删除一个表的所有行,使用TRUNCATE TABLE tbl_name 而不要用DELETE FROM tbl_name。

4、其它优化技巧

下面列出了提高查询速度的各种技巧:

1) 使用持久的连接数据库以避免连接开销。如果不能使用持久的连接并且你正启动许多新的与数据库的连接,可能要更改 thread_cache_size 变量的值。

2) 总是检查所有查询确实使用已经在表中创建了的索引。在MySQL中,可以用EXPLAIN命令做到。

3) 尝试避免在频繁更新的表上执行复杂的SELECT查询,以避免与锁定表有关的由于读、写冲突发生的问题。

4) 对于没有删除的行的MyISAM表,可以在另一个查询正从表中读取的同时在末尾插入行。如果这很重要,应考虑按照避免删除行的方式使用表。另一个可能性是在删除大量行后运行 OPTIMIZE TABLE 。

5) 要修复任何ARCHIVE表可以发生的压缩问题,可以执行 OPTIMIZE TABLE 。

6) 如果你主要按expr1,expr2,...顺序检索行,使用 ALTER TABLE ... ORDER BY expr1, expr2, ... 。对表大量更改后使用该选项,可以获得更好的性能。

7) 在一些情况下,使得基于来自其它表的列的信息引入一个“ 哈希”的列有意义。如果该列较短并且有合理的唯一值,它可以比在许多列上的一个大索引快些。在MySQL中,很容易使用这个额外列:

SELECT * FROM tbl_name WHERE hash_col=MD5(CONCAT(col1,col2)) AND col1='constant' AND col2='constant';

8) 对于频繁更改的MyISAM表,应试图避免所有变长列(VARCHAR、BLOB和TEXT)。如果表包括单一的变长列则使用动态记录格式。

9) 只是因为行太大,将一张表分割为不同的表一般没有什么用处。为了访问行,最大的性能冲击是磁盘搜索以找到行的第一个字节。在找到数据后,大多数新型磁盘对大多数应用程序来说足够快,能读入整个行。确实有必要分割的唯一情形是如果它是使用动态记录格式使之变为固定的记录大小的MyISAM表(见上述),或如果你需要很频繁地扫描表而不需要大多数列。

10) 如果你需要很经常地计算结果,例如基于来自很多行的信息的计数,引入一个新表并实时更新计数器可能更好一些。下面形式的更新会更快一些:

UPDATE tbl_name SET count_col=count_col+1 WHERE key_col=constant;

当你使用象MyISAM那样的只有表级锁定的MySQL存储引擎(多重读/单个写)时,这确实很重要。这也给大多数数据库较好的性能,因为行锁定管理器在这种情况下有较少的事情。

11)如果你需要从大的记录文件表中收集统计信息,使用总结性的表而不是扫描整个表。维护总结应该比尝试做“实时”统计要快些。当有变化时从日志重新生成新的总结表比改变运行的应用(取决于业务决策)要快得多:

上一页12下一页


留言