网络安全 频道

从MySQL得到最大的性能

10.7 其他优化技巧
对加快系统的未分类的建议是:

使用持久的连接数据库以避免连接开销。
总是检查你的所有询问确实使用你已在表中创建了的索引。在MySQL中,你可以用EXPLAIN命令做到。见7.22 EXPLAIN句法(得到关于SELECT的信息)。
尝试避免在被更改了很多的表上的复杂的SELECT查询。这避免与锁定表有关的问题。
在一些情况下,使得基于来自其他表的列的信息引入一个“ 哈希”的列有意义。如果该列较短并且有合理的唯一值,它可以比在许多列上的一个大索引快些。在MySQL中,很容易使用这个额外列:SELECT * from table where hash=calculated hash on col1 and col2 and col_1=constant and col_2=constant and .. 。
对于有很多更改的表,你应该试着避免所有VARCHAR或BLOB列。只要你使用单个VARCHAR或BLOB列,你将得到动态行长度。见9.4 MySQL表类型。
只是因为行太大,分割一张表为不同的表一般没有什么用处。为了存取行,最大的性能命冲击是磁盘寻道以找到行的第一个字节。在找到数据后,大多数新型磁盘对大多数应用程序来说足够快,能读入整个行。它确实有必要分割的唯一情形是如果其动态行尺寸的表(见上述)能变为固定的行大小,或如果你很频繁地需要扫描表格而不需要大多数列。见9.4 MySQL表类型。
如果你很经常地需要基于来自很多行的信息计算(如计数),引入一个新表并实时更新计数器可能更好一些。类型的更改UPDATE table set count=count+1 where index_column=constant是很快的!当你使用象MySQL那样的只有表级锁定(多重读/单个写)的数据库时,这确实重要。这也将给出大多数数据库较好的性能,因为锁定管理器在这种情况下有较少的事情要做。 11111111111111111111111
如果你需要从大的记录文件表中收集统计信息,使用总结性的表而不是扫描整个表。维护总结应该比尝试做“实时”统计要快些。当有变化而不是必须改变运行的应用时,从记录文件重新生成新的总结表(取决于业务决策)要快多了!
如果可能,应该将报告分类为“实时”或“统计”,这里统计报告所需的数据仅仅基于从实际数据产生的总结表中产生。
充分利用列有缺省值的事实。当被插入值不同于缺省值时,只是明确地插入值。这减少MySQL需要做的语法分析并且改进插入速度。
在一些情况下,包装并存储数据到一个BLOB中是很方便的。在这种情况下,你必须在你的应用中增加额外的代码来打包/解包BLOB中的东西,但是这种方法可以在某些阶段节省很多存取。当你有不符合静态的表结构的数据时,这很实用。
在一般情况下,你应该尝试以第三范式保存数据,但是如果你需要这些以获得更快的速度,你应该不用担心重复或创建总结表。
存储过程或UDF(用户定义函数)可能是获得更好性能的一个好方法,然而如果你使用某些不支持它的数据库,在这种情况中,你应该总是有零一个方法(较慢的)做这些。
你总是能通过在你的应用程序中缓冲查询/答案并尝试同时做很多插入/更新来获得一些好处。如果你的数据库支持锁定表(象MySQL和Oracle),这应该有助于确保索引缓冲在所有更新后只清空一次。
但你不知道何时写入你的数据时,使用INSERT /*! DELAYED */。这加快处理,因为很多记录可以用一次磁盘写入被写入。
当你想要让你的选择显得更重要时,使用INSERT /*! LOW_PRIORITY */。
使用SELECT /*! HIGH_PRIORITY */来取得塞入队列的选择,它是即使有人等待做一个写入也要完成的选择。
使用多行INSERT语句来存储很多有一条SQL命令的行(许多SQL服务器支持它)。
使用LOAD DATA INFILE装载较大数量的数据。这比一般的插入快并且当myisamchk集成在mysqld中时,甚至将更快。
使用AUTO_INCREMENT列构成唯一值。
当使用动态表格式时,偶尔使用OPTIMIZE TABLE以避免碎片。见7.9O PTIMIZE TABLE句法。
可能时使用HEAP表以得到更快的速度。见9.4 MySQL表类型。
当使用一个正常Web服务器设置时,图象应该作为文件存储。这仅在数据库中存储的一本文件的引用。这样做的主要原因是是一个正常的Web服务器在缓冲文件比数据库内容要好得多,因此如果你正在使用文件,较容易得到一个较快的系统。
对经常存取的不重要数据(象有关对没有cookie用户最后显示标语的信息)使用内存表。
在不同表中具有相同信息的列应该被声明为相同的并有相同的名字。在版本 3.23 前,你只能靠较慢的联结。尝试使名字简单化(在客户表中使用name而不是customer_name)。为了使你的名字能移植到其他SQL服务器,你应该使他们短于18 个字符。
如果你需要确实很高的速度,你应该研究一下不同SQL服务器支持的数据存储的底层接口!例如直接存取MySQL MyISAM,比起使用SQL 接口,你能得到2-5倍的速度提升。然而为了能做到它,数据必须是在与应用程序性在同一台机器的服务器上,并且通常它只应该被一个进程存取(因为外部文件锁定确实很慢)。通过在MySQL服务器中引进底层MyISAM命令能消除以上问题(如果需要,这可能是获得更好性能的一个容易的方法)。借助精心设计的数据库接口,应该相当容易支持这类优化。
在许多情况下,从一个数据库存取数据(使用一个实时连接)比存取一个文本文件快些,只是因为数据库比文本文件更紧凑(如果你使用数字数据)并且这将涉及更少的磁盘存取。你也节省代码,因为你不须分析你的文本文件来找出行和列的边界。
你也能使用复制加速。见19.1 数据库复制。
10.8 使用你自己的基准测试
你决定应该测试你的应用程序和数据库,以发现瓶颈在哪儿。通过修正它(或通过用一个“哑模块”代替瓶颈),你能容易确定下一个瓶颈(等等)。即使对你的应用程序来说,整体性能“足够好”,你至少应该对每个瓶颈做一个“计划”,如果某人“确实需要修正它”,如何解决它。

对于一些可移植的基准程序的例子,参见MySQL基准套件。见11 MySQL 基准套件。你能利用这个套件的任何程序并且为你的需要修改它。通过这样做,你能尝试不同的你的问题的解决方案并测试哪一个对你是最快的解决方案。

在系统负载繁重时发生一些问题是很普遍的,并且我们有很多与我们联系的客户,他们在生产系统中有一个(测试)系统并且有负载问题。到目前为止,被一种这些的情况是与基本设计有关的问题(表扫描在高负载时表现不好)或OS/库问题。如果系统已经不在生产系统中,它们大多数将很容易修正。

为了避免这样的问题,你应该把一些力气放在在可能最坏的负载下测试你的整个应用!

10.9 设计选择
MySQL在分开的文件中存储行数据和索引数据。许多(几乎全部)其他数据库在同一个文件中混合行和索引数据。我们相信,MySQL的选择对非常广泛的现代系统的来说是较好的。

存储行数据的另一个方法是在一个分开的区域保存每列信息(例子是SDBM和Focus)。这将对每个存取多于一列的查询获得一个性能突破。因为在多于一列被存取时,这快速退化,我们相信这个模型对通用功能的数据库不是最好。

更常见的情形是索引和数据一起被存储(就象Oracle/Sybase)。在这种情况中,你将在索引的叶子页面上找到行信息。有这布局的好处是它在许多情况下(取决于这个索引被缓冲得怎样)节省一次磁盘读。有这布局的坏处是:

表扫描更慢,因为你必须读完索引以获得数据。
你损失很多空间,因为你必须重复来自节点的索引(因为你不能在节点上存储行)
删除将随时间变化恶化数据库表(因为节点中的索引在删除后通常不被更新)。
你不能仅使用索引表为一个查询检索数据。
索引数据很难缓冲。
10.10 MySQL设计局限/折衷
因为MySQL使用极快的表锁定(多次读/一次写),留下的最大问题是在同一个表中的一个插入的稳定数据流与慢速选择的一个混合。

我们相信,在其他情况下,对大多数系统,异常快速的性能使它成为一个赢家。这种情形通常也可能通过表的多个副本来解决,但是它要花更多的力气和硬件。

对一些常见的应用环境,我们也在开发一些扩展功能以解决此问题。

10.11 可移植性
因为所有SQL服务器实现了SQL的不同部分,要花功夫编写可移植的SQL应用程序。对很简单的选择/插入,它是很容易的,但是你需要越多,它越困难,而且如果你想要应用程序对很多数据库都快,它变得更难!

为了使一个复杂应用程序可移植,你需要选择它应该与之工作的很多SQL服务器。

当你能使用MySQL的crash-me 程序(http://www.mysql.com/crash-me-choose.htmy)来找出你能与之使用的数据库服务器的选择的函数、类型和限制。crash-me现在对任何可能的事情测试了很长时间,但是它仍然理解测试过的大约450件事情。

例如,如果你想要能使用Informix 或 DB2,你不应该有比18个字符更长的列名。

MySQL基准程序和crash-me是独立于数据库的。通过观察我们怎么处理它,你能得到一个感觉,你必须为编写你的独立于数据库的应用程序做什么。基准本身可在MySQL源代码分发的“sql-bench”目录下找到。他们用DBI数据库接口以Perl写成(它解决问题的存取部分)。

http://www.mysql.com/benchmark.html看这个基准的结果。

正如你可在这些结果看见的那样,所有数据库都有一些弱点。这就是他们不同的设计折衷导致的不同行为。

如果你为数据库的独立性而努力,你需要获得每个SQL服务器瓶颈的良好感受。MySQL在检索和更新方面很快,但是在同一个表上混合读者/写者方面将有一个问题。在另一方面,当你试图存取你最近更新了的行时,Oracle有一个很大问题(直到他们被清空到磁盘上)。事务数据库总的来说在从记录文件表中生成总结表不是很好,因为在这种情况下,行级锁定几乎没用处。

为了使你的应用程序“确实独立于数据库”,你需要定义一个容易的可扩展的接口,用它你可操纵你的数据。因为C++在大多数系统上可以得到的,使用数据库的一个C++ 类接口是有意义的。

如果你使用一些某个数据库特定的功能(在MySQL中,象REPLACE命令),你应该为SQL服务器编码一个方法以实现同样的功能 (但是慢些)。用MySQL,你能使用/*! */语法把MySQL特定的关键词加到查询中。在/**/中的代码将被大多数其他SQL服务器视为一篇注释(被忽略)。

如果高性能真的比准确性更重要,就像在一些web应用程序那样。一种可能性是创建一个应用层,缓冲所有的结果以给你更高的性能。通过只是让老的结果在短时间后‘过期’,你能保持缓存合理地刷新。这在极高负载的情况下是相当不错的,在此情况下,你能动态地增加缓存到更大并且设定较高的过期时限直到一切回到正常。

在这种情况下,创建信息的表应该包含缓存初始大小和表一般应该被刷新几次的信息。

10.12 我们已将MySQL用在何处?
在MySQL起初开发期间,MySQL的功能适合我们的最大客户。他们为在瑞典的一些最大的零售商处理数据仓库。

我们从所有商店得到所有红利卡交易的每周总结并且我们被期望为所有店主提供有用的信息以帮助他们得出他们的广告战如何影响他们的顾客。

数据是相当巨量的(大约每月7百万宗交易总结)并且我们保存4-10年来的数据需要呈现给用户。我们每周顾客那里得到请求,他们想要“立刻”访问来自该数据的新报告。

我们通过每月将所有信息存储在压缩的“交易”表中来解决它。我们有一套简单的宏/脚本用来生成来自交易表的不同条件( 产品组,顾客id,商店...)的总结表。报告是由一个进行语法分析网页的小perl脚本动态生成的网页,在脚本中执行SQL语句并且插入结果。现在我们很想使用PHP或mod_perl,但是那时他们没有。

对图形数据,我们用C语言编写了一个简单的工具,它能基于SQL查询的结果(对结果的一些处理)产生赠品,这也从分析HTML文件的perl脚本中动态地执行。

在大多数情况下,一个新的报告通过简单地复制一个现有脚本并且修改其中的SQL查询来完成。在一些情况下,我们将需要把更多的字段加到一个现有的总结表中或产生一个新的,但是这也相当简单,因为我们在磁盘上保存所有交易表。(目前我们有至少50G的交易表和200G的其他顾客数据)。

我们也让我们的顾客直接用ODBC存取总结表以便高级用户能自己试验数据。

我们用非常中档的Sun Ultra sparcstation ( 2x200 Mz )来处理,没有任何问题。最近我们升级了服务器之一到一台2个CPU 400 Mz的Ultra sparc,并且我们现在计划处理产品级的交易,这将意味着数据增加10番。我们认为我们能通过只是为我们的系统增加更多的磁盘就能赶上它。

我们也在试验Intel-Linux以便能更便宜地得到更多的cpu动力。既然我们有二进制可移植的数据库格式(在3.32中引入),我们将开始在应用程序的某些部分使用它。

我们最初的感觉是Linux在低到中等负载时执行的较好,但是你开始得到导致的高负载时,Solaris将表现更好,因为磁盘IO的极限,但是我们还没有关于这方面的任何结论。在与一些Linux核心开发者的讨论以后,这可能是 Linux 的副作用,它给批处理以太多的资源使得交互的性能变得很低。当大的批处理正在进行时,这使机器感觉很慢且无反应。希望这将在未来的Linux内核中解决。

 http://netadmin.77169.com/HTML/20050124005100.html

0
相关文章