﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-Java天空 任我翱翔-随笔分类-MySQL</title><link>http://www.blogjava.net/persister/category/46174.html</link><description /><language>zh-cn</language><lastBuildDate>Wed, 13 Oct 2010 21:33:30 GMT</lastBuildDate><pubDate>Wed, 13 Oct 2010 21:33:30 GMT</pubDate><ttl>60</ttl><item><title>MySQL导入导入命令总结</title><link>http://www.blogjava.net/persister/archive/2010/07/14/326107.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Wed, 14 Jul 2010 09:52:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2010/07/14/326107.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/326107.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2010/07/14/326107.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/326107.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/326107.html</trackback:ping><description><![CDATA[MySQL提供了几种可供选择的数据导入导出方式。<br />
<br />
基本分为两种形式，一种是sql形式的数据导入导出(mysqldump,mysql,source)，另一种是自定义数据的导入导出(load data infile, into outfile)。<br />
<br />
自定义数据格式的导入导出有一个好处就是数据可以是csv格式的，而且用的非常多。比如大型的数据，如果往查询到数据然后写到excel里面，效率肯定是一个问题。但是用mysql的自带的命令，那么就可以让mysql自己生成csv文件，这样速度会快不少。导入也是一样，就是数据文件可以传到服务器上，然后使用mysql的命令导入到数据库中，比读csv格式的文件然后插入到数据库中效率会提高不少。<br />
<br />
<br />
下面附上这些命令的具体描述：<br />
<br />
mysql中Load Data InFile是用于批量向数据表中导入记录。<br />
首先创建一个表<br />
Use Test;<br />
Create Table TableTest(<br />
`ID` mediumint(8) default '0',<br />
`Name` varchar(100) default ''<br />
) TYPE=MyISAM;<br />
<br />
向数据表导入数据<br />
Load Data InFile 'D:/Data.txt' Into Table `TableTest`<br />
<br />
常用如下：<br />
Load Data InFile 'D:/Data.txt' Into Table `TableTest` Lines Terminated By '"r"n';<br />
这个语句，字段默认用制表符隔开，每条记录用换行符隔开，在Windows下换行符为&#8220;"r"n&#8221;<br />
D:/Data.txt 文件内容如下面两行：<br />
1 A<br />
2 B<br />
&#8220;1&#8221;和&#8220;A&#8221;之间有一个制表符<br />
这样就导进两条记录了。<br />
<br />
自定义语法<br />
Load Data InFile 'D:/Data.txt' Into Table `TableTest` Fields Terminated By ',' Enclosed By '"' <br />
<br />
Escaped By '"' Lines Terminated By '"r"n';<br />
Fields Terminated By ',' Enclosed By '"' Escaped By '"'<br />
表示每个字段用逗号分开，内容包含在双引号内<br />
Lines Terminated By '"r"n';<br />
表示每条数据用换行符分开<br />
<br />
<br />
导入数据库<br />
常用source 命令<br />
进入mysql数据库控制台，<br />
如mysql -u root -p<br />
<br />
mysql&gt;use 数据库<br />
<br />
然后使用source命令，后面参数为脚本文件（如这里用到的.sql）<br />
mysql&gt;source d:"wcnc_db.sql<br />
<br />
也可以使用mysql命令（在bin目录下）<br />
.../bin/mysql db1 &gt; xx.sql;<br />
<br />
<br />
和 Load Data InFile 相反的是<br />
Select * From `TableTest` Into OutFile 'D:/Data_OutFile.txt';<br />
把表的数据导出<br />
<br />
<br />
Using command line tools to export data from a MySQL database into a CSV file is quite easy. Here's <br />
<br />
how:<br />
<br />
mysql -uexampleuser -pletmein exampledb -B -e "select * from "`person"`;" | sed 's/<br />
<br />
"t/","/g;s/^/"/;s/$/"/;s/"n//g' &gt; filename.csv<br />
<br />
Here is some sample output of the above:<br />
<br />
"id","username","group","password"<br />
"1","tux","admin","5f4dcc3b5aa765d61d8327deb882cf99"<br />
"2","tlugian","admin","5f4dcc3b5aa765d61d8327deb882cf99"<br />
"3","saiyuki","admin","5f4dcc3b5aa765d61d8327deb882cf99"<br />
"4","fred","staff","5f4dcc3b5aa765d61d8327deb882cf99"<br />
"5","barney","staff","5f4dcc3b5aa765d61d8327deb882cf99"<br />
"6","wilma","admin","5f4dcc3b5aa765d61d8327deb882cf99"<br />
<br />
And now for the explanation:<br />
<br />
Starting with the MySQL command. I wont explain the -u and -p options they are straight forward (if <br />
<br />
in doubt man mysql). The -B option will delimit the data using tabs and each row will appear on a <br />
<br />
new line. The -e option denotes the command to run once you have logged into the database. In this <br />
<br />
case we are using a simple SELECT statement.<br />
<br />
Onto sed. The command used here contains three seperate sed scripts:<br />
<br />
s/"t/","/g;s/^/"/&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;--- this will search and replace all occurences of 'tabs' and replace them <br />
<br />
with a ",".<br />
<br />
;s/$/"/;&nbsp;&nbsp;&nbsp; &lt;--- This will place a " at the start of the line.<br />
<br />
s/"n//g&nbsp;&nbsp;&nbsp; &lt;---- This will place a " at the end of the line.<br />
<br />
After running the result set through sed we redirect the output to a file with a .csv extension.<br />
<br />
<br />
<br />
mysqldump命令的输入是在bin目录下.<br />
1.导出整个数据库<br />
<br />
mysqldump -u 用户名 -p 数据库名 &gt; 导出的文件名<br />
<br />
mysqldump -u wcnc -p smgp_apps_wcnc &gt; wcnc.sql<br />
<br />
2.导出一个表<br />
<br />
mysqldump -u 用户名 -p 数据库名 表名&gt; 导出文件的路径和名称<br />
<br />
mysqldump -u wcnc -p smgp_apps_wcnc users&gt; wcnc_users.sql<br />
<br />
<br />
<br />
<br />
<img src ="http://www.blogjava.net/persister/aggbug/326107.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2010-07-14 17:52 <a href="http://www.blogjava.net/persister/archive/2010/07/14/326107.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MySQL Show processlist命令功能</title><link>http://www.blogjava.net/persister/archive/2010/07/13/325975.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Tue, 13 Jul 2010 08:15:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2010/07/13/325975.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/325975.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2010/07/13/325975.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/325975.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/325975.html</trackback:ping><description><![CDATA[怎么查看服务器的运行情况，比如多少查询，管理客户端的查询等：<br />
<br />
show processlist<br />
<br />
<span><span>mysql&gt; show processlist;<br />
+-----+-------------+--------------------+-------+---------+-------+----------------------------------+----------<br />
|
Id | User&nbsp; | Host&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | db&nbsp;&nbsp; | Command | Time| State&nbsp;&nbsp;&nbsp;&nbsp; |
Info&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<br />
+-----+-------------+--------------------+-------+---------+-------+----------------------------------+----------<br />
|207|root&nbsp;
|192.168.0.20:51718 |mytest | Sleep&nbsp;&nbsp;&nbsp; | 5&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |
NULL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<br />
|208|root&nbsp; |192.168.0.20:51719 |mytest | Sleep&nbsp;&nbsp;&nbsp; | 5&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; |
NULL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
|220|root&nbsp; |192.168.0.20:51731 |mytest |Query&nbsp;&nbsp;&nbsp; | 84&nbsp;&nbsp;
| Locked&nbsp; |<br />
select bookname,culture,value,type&nbsp; from book where
id=001<br />
先简单说一下各列的含义和用途，第一列，id，不用说了吧，一个标识，你要kill一个语句的时候很有用，比如我们进行了一个非常耗时的查询，想停止的时候，就只有采用这个命令了。<br />
<br />
user列，显示当前用户，如果不是root，这个命令就只显示你权限范围内的sql语句。<br />
<br />
host列，显示这个语句是从哪个ip的哪个端口上发出的，可以用来追踪出问题语句的用户。<br />
<br />
db列，显示这个进程目前连接的是哪个数据库。<br />
<br />
command列，显示当前连接的执行的命令，一般就是休眠（sleep），查询
（query），连接（connect）。time列，此这个状态持续的时间，单位是秒。<br />
<br />
state列，显示使用当前连接的sql语句的状态，很重要的列，后续会有所有的状态的描述，请注意，state只是语句执行中的某一个状态，一个sql语句，已查询为例，可能需要经过copying to tmp
table，Sorting result，Sending data等状态才可以完成，info列，显示这个sql语句</span></span>。<br />
<br />
注意权限，通常只能看到自己的查询process，是看不到其他人的process的。<br />
<br />
<br />
<br />
<img src ="http://www.blogjava.net/persister/aggbug/325975.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2010-07-13 16:15 <a href="http://www.blogjava.net/persister/archive/2010/07/13/325975.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MySQL忘记root密码怎么办？</title><link>http://www.blogjava.net/persister/archive/2010/03/24/316461.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Wed, 24 Mar 2010 09:26:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2010/03/24/316461.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/316461.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2010/03/24/316461.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/316461.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/316461.html</trackback:ping><description><![CDATA[如果 MySQL 正在运行，到Windows的服务那里停止MySQL。 <br />
启动 MySQL：mysqld
--skip-grant-tables；<br />
就可以不需要密码就进入 MySQL 了。 <br />
然后就是 <br />
&gt;use
mysql <br />
&gt;update user set password=password("new_pass") where
user="root"; <br />
&gt;flush privileges; <br />
重新杀 MySQL ，用正常方法启动 MySQL 。<br />
<br />
这里有一个地方要注意，就是有可能，user表中根本就没有root这个用户。<br />
<img src ="http://www.blogjava.net/persister/aggbug/316461.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2010-03-24 17:26 <a href="http://www.blogjava.net/persister/archive/2010/03/24/316461.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MYSQL Master-Slave配置和实现原理</title><link>http://www.blogjava.net/persister/archive/2009/09/09/294507.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Wed, 09 Sep 2009 12:37:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/09/09/294507.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/294507.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/09/09/294507.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/294507.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/294507.html</trackback:ping><description><![CDATA[The target uses for replication in MySQL include: <br />
<ul>
    <li>
    <p>
    Scale-out solutions - spreading the load among multiple slaves
    to improve performance. In this environment, all writes and
    updates must take place on the master server. Reads, however,
    may take place on one or more slaves. This model can improve the
    performance of writes (since the master is dedicated to
    updates), while dramatically increasing read speed across an
    increasing number of slaves.
    </p>
    </li>
    <li>
    <p>
    Data security - because data is replicated to the slave, and the
    slave can pause the replication process, it is possible to run
    backup services on the slave without corrupting the
    corresponding master data.
    </p>
    </li>
    <li>
    <p>
    Analytics - live data can be created on the master, while the
    analysis of the information can take place on the slave without
    affecting the performance of the master.
    </p>
    </li>
    <li>
    <p>
    Long-distance data distribution - if a branch office would like
    to work with a copy of your main data, you can use replication
    to create a local copy of the data for their use without
    requiring permanent access to the master。<br />
    </p>
    </li>
</ul>
配置参考mysql<a href="http://dev.mysql.com/doc/refman/5.1/en/replication.html">官方文档</a>，按照配置文档，我具体测试了一下，没有问题，大概的配置步骤如下：<br />
<br />
<br />
<strong><br />
1、Master端的my.cnf配置</strong><br />
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 255);">log</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">bin<br />
server</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">id</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(128, 0, 0);">1</span><span style="color: rgb(0, 0, 0);"><br />
sql</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">bin</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">update</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">same<br />
binlog</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 255);">do</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">db</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">vbb</span></div>
<br />
<strong>2、Slave端的my.cnf配置</strong><br />
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 0);">master</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">host</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">192.168</span><span style="color: rgb(0, 0, 0);">.</span><span style="color: rgb(0, 0, 0);">22.25</span><span style="color: rgb(0, 0, 0);"><br />
master</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">user</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">salve<br />
master</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">password</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">123456</span><span style="color: rgb(0, 0, 0);"><br />
master</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">port</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">3306</span><span style="color: rgb(0, 0, 0);"><br />
server</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">id</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);"><br />
master</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">connect</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">retry</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">60</span><span style="color: rgb(0, 0, 0);">&nbsp;预设重试间隔60秒</span></div>
<br />
<strong>3、复制</strong><br />
<div style="background-color: rgb(238, 238, 238); font-size: 13px; border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 0);">CHANGE&nbsp;MASTER&nbsp;to </span><span style="color: rgb(0, 0, 0);">MASTER_LOG_FILE</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0); font-weight: bold;">'</span><span style="color: rgb(0, 0, 0); font-weight: bold;">mysql-bin.000006</span><span style="color: rgb(0, 0, 0); font-weight: bold;">'</span><span style="color: rgb(0, 0, 0);">,</span><span style="color: rgb(0, 0, 0);">&nbsp;MASTER_LOG_POS</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(128, 0, 0);">98</span></div>
<br />
具体配置有一些细节，看官方文档即可。<br />
<br />
这里具体说一下其原理：<br />
<br />
<p><font face="Times New Roman"><strong>1、复制进程</strong><br />
Mysql的复制（Replication）是一个异步的复制，从一个Mysql instace（称之为Master）复制到另一个Mysql
instance（称之Slave）。实现整个复制操作主要由三个进程完成的，其中两个进程在Slave（Sql进程和IO进程），另外一个进程在
Master（IO进程）上。<br />
要实施复制，首先必须打开Master端的binary log（bin-log）功能，否则无法实现。因为整个复制过程实际上就是Slave从Master端获取该日志然后再在自己身上完全顺序的执行日志中所记录的各种操作。<br />
复制的基本过程如下：<br />
1)、Slave上面的IO进程连接上Master，并请求从指定日志文件的指定位置（或者从最开始的日志）之后的日志内容；<br />
</font><font face="Times New Roman"><br />
2)、Master接收到来自Slave的IO进程的请求后，通过负责复制的IO进程根据请求信息读取制定日志指定位置之后的日志信息，返回给Slave
的IO进程。返回信息中除了日志所包含的信息之外，还包括本次返回的信息已经到Master端的bin-log文件的名称以及bin-log的位置；<br />
<br />
3)、Slave的IO进程接收到信息后，将接收到的日志内容依次添加到Slave端的relay-log文件的最末端，并将读取到的Master端的
bin-log的文件名和位置记录到master-info文件中，以便在下一次读取的时候能够清楚的告诉Master&#8220;我需要从某个bin-log的哪
个位置开始往后的日志内容，请发给我&#8221;；<br />
<br />
4)、Slave的Sql进程检测到relay-log中新增加了内容后，会马上解析relay-log的内容成为在Master端真实执行时候的那些可执行的内容，并在自身执行。<br />
实际上在老版本的Mysql的复制实现在Slave端并不是两个进程完成的，而是由一个进程完成。但是后来发现这样做存在较大的风险和性能问题，主要如下：<br />
首先，一个进程就使复制bin-log日志和解析日志并在自身执行的过程成为一个串行的过程，性能受到了一定的限制，异步复制的延迟也会比较长。<br />
另外，Slave端从Master端获取bin-log过来之后，需要接着解析日志内容，然后在自身执行。在这个过程中，Master端可能又产生了大量
变化并声称了大量的日志。如果在这个阶段Master端的存储出现了无法修复的错误，那么在这个阶段所产生的所有变更都将永远无法找回。如果在Slave
端的压力比较大的时候，这个过程的时间可能会比较长。<br />
所以，后面版本的Mysql为了解决这个风险并提高复制的性能，将Slave端的复制改为两个进程来完成。提出这个改进方案的人是Yahoo!的一位工程
师&#8220;Jeremy
Zawodny&#8221;。这样既解决了性能问题，又缩短了异步的延时时间，同时也减少了可能存在的数据丢失量。当然，即使是换成了现在这样两个线程处理以后，同
样也还是存在slave数据延时以及数据丢失的可能性的，毕竟这个复制是异步的。只要数据的更改不是在一个事物中，这些问题都是会存在的。如果要完全避免
这些问题，就只能用mysql的cluster来解决了。不过mysql的cluster是内存数据库的解决方案，需要将所有数据都load到内存中，这
样就对内存的要求就非常大了，对于一般的应用来说可实施性不是太大。<br />
</font></p>
<p><font face="Times New Roman"><strong>2、复制实现级别</strong><br />
Mysql的复制可以是基于一条语句（Statement level），也可以是基于一条记录（Row level），可以在Mysql的配置参数中设定这个复制级别，不同复制级别的设置会影响到Master端的bin-log记录成不同的形式。<br />
Row Level：日志中会记录成每一行数据被修改的形式，然后在slave端再对相同的数据进行修改。<br />
优点：在row
level模式下，bin-log中可以不记录执行的sql语句的上下文相关的信息，仅仅只需要记录那一条记录被修改了，修改成什么样了。所以row
level的日志内容会非常清楚的记录下每一行数据修改的细节，非常容易理解。而且不会出现某些特定情况下的存储过程，或function，以及
trigger的调用和触发无法被正确复制的问题。<br />
缺点：row
level下，所有的执行的语句当记录到日志中的时候，都将以每行记录的修改来记录，这样可能会产生大量的日志内容，比如有这样一条update语
句：update product set owner_member_id = &#8216;b&#8217; where owner_member_id =
&#8216;a&#8217;，执行之后，日志中记录的不是这条update语句所对应额事件（mysql以事件的形式来记录bin-log日志），而是这条语句所更新的每一条
记录的变化情况，这样就记录成很多条记录被更新的很多个事件。自然，bin-log日志的量就会很大。尤其是当执行alter
table之类的语句的时候，产生的日志量是惊人的。因为Mysql对于alter
table之类的表结构变更语句的处理方式是整个表的每一条记录都需要变动，实际上就是重建了整个表。那么该表的每一条记录都会被记录到日志中。<br />
Statement Level:每一条会修改数据的sql都会记录到 master的bin-log中。slave在复制的时候sql进程会解析成和原来master端执行过的相同的sql来再次执行。<br />
优点：statement level下的优点首先就是解决了row level下的缺点，不需要记录每一行数据的变化，减少bin-log日志量，节约IO，提高性能。因为他只需要记录在Master上所执行的语句的细节，以及执行语句时候的上下文的信息。<br />
缺点：由于他是记录的执行语句，所以，为了让这些语句在slave端也能正确执行，那么他还必须记录每条语句在执行的时候的一些相关信息，也就是上下文信
息，以保证所有语句在slave端杯执行的时候能够得到和在master端执行时候相同的结果。另外就是，由于Mysql现在发展比较快，很多的新功能不
断的加入，使mysql得复制遇到了不小的挑战，自然复制的时候涉及到越复杂的内容，bug也就越容易出现。在statement
level下，目前已经发现的就有不少情况会造成mysql的复制出现问题，主要是修改数据的时候使用了某些特定的函数或者功能的时候会出现，比
如：sleep()函数在有些版本中就不能真确复制，在存储过程中使用了last_insert_id()函数，可能会使slave和master上得到
不一致的id等等。由于row level是基于每一行来记录的变化，所以不会出现类似的问题。</font></p>
<p>With statement-based replication, you may encounter issues with
replicating stored routines or triggers. You can avoid these
issues by using row-based replication instead.</p>
<p><font face="Times New Roman">
从官方文档中看到，之前的Mysql一直都只有基于statement的复制模式，直到5.1.5版本的Mysql才开始支持row
level的复制。从5.0开始，Mysql的复制已经解决了大量老版本中出现的无法正确复制的问题。但是由于存储过程的出现，给Mysql的复制又带来
了更大的新挑战。另外，看到官方文档说，从5.1.8版本开始，Mysql提供了除Statement Level和Row
Level之外的第三种复制模式：Mixed，实际上就是前两种模式的结合。</font></p>
<p>From MySQL 5.1.12 to MySQL
5.1.28, mixed format is the default. Beginning with MySQL 5.1.29,
statement-based format is the default.
</p>
<p><font face="Times New Roman">在Mixed模式下，Mysql会根据执行的每一条具体的sql语句来区分对
待记录的日志形式，也就是在Statement和Row之间选择一种。新版本中的Statment
level还是和以前一样，仅仅记录执行的语句。而新版本的Mysql中队row level模式也被做了优化，并不是所有的修改都会以row
level来记录，像遇到表结构变更的时候就会以statement模式来记录，如果sql语句确实就是update或者delete等修改数据的语句，
那么还是会记录所有行的变更。<br />
</font></p>
<font face="Times New Roman"><strong>3、复制常用架构</strong><br />
Mysql复制环境90%以上都是一个Master带一个或者多个Slave的架构模式，主要用于读压力比较大的应用的数据库端廉价扩展解决方案。因为只
要master和slave的压力不是太大（尤其是slave端压力）的话，异步复制的延时一般都很少很少。尤其是自slave端的复制方式改成两个进程
处理之后，更是减小了slave端的延时。而带来的效益是，对于数据实时性要求不是特别的敏感度的应用，只需要通过廉价的pc
server来扩展slave的数量，将读压力分散到多台slave的机器上面，即可解决数据库端的读压力瓶颈。这在很大程度上解决了目前很多中小型网站
的数据库压力瓶颈问题，甚至有些大型网站也在使用类似方案解决数据库瓶颈。<br />
一个Master带多个slave的架构实施非常简单，多个slave和单个slave的实施并没有太大区别。在Master端并不care有多少个
slave连上了master端，只要有slave进程通过了连接认证，向他请求binlog信息，他就会按照连接上来的io进程的要求，读取自己的
binlog信息，返回给slave的IO进程。对于slave的配置细节，在Mysql的官方文档上面已经说的很清楚了，甚至介绍了多种实现slave
的配置方法。</font><br />
<img src ="http://www.blogjava.net/persister/aggbug/294507.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-09-09 20:37 <a href="http://www.blogjava.net/persister/archive/2009/09/09/294507.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MySQL Index</title><link>http://www.blogjava.net/persister/archive/2009/08/20/291923.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Thu, 20 Aug 2009 03:37:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/08/20/291923.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/291923.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/08/20/291923.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/291923.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/291923.html</trackback:ping><description><![CDATA[<span style="font-family: 宋体;">这篇文章摘自网络，已经找不到原文出处了，写的不错，学习一下。<br />
<br />
数据库的索引</span>
<p class="MsoNormal"><span lang="EN-US">1. </span><span style="font-family: 宋体;">如果不建立索引，那么查询都需要全表扫描；如果建立了索引，则数据库会保存一个索引文件通常是特殊的结构比如</span><span lang="EN-US">B</span><span style="font-family: 宋体;">树，这样查询起来不需要全表扫描，一下子能够找到满足要求的记录。</span></p>
<p class="MsoNormal"><span lang="EN-US">2. </span><span style="font-family: 宋体;">一般是对</span><span lang="EN-US">Where</span><span style="font-family: 宋体;">之后的条件建立索引，数据库中的主键是已经建立了索引的。数据库中可以建立多个索引。</span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">3. </span><span style="font-family: 宋体;">可以对不同类型的列建立索引。</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">对于</span><span lang="EN-US">Text</span><span style="font-family: 宋体;">类型等，可以使用</span><span lang="EN-US">MySQL</span><span style="font-family: 宋体;">的全文检索功能建立全文索引。它利用了自然语言的方法去在文本中检索关键词。</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">举个例子：如果使用</span><span lang="EN-US">=</span><span style="font-family: 宋体;">号的话可能需要使用</span><span lang="EN-US">like</span><span style="font-family: 宋体;">以及</span><span lang="EN-US">%</span><span style="font-family: 宋体;">等去匹配。而使用</span><span lang="EN-US">MySQL</span><span style="font-family: 宋体;">的全文检索可以使用</span><span lang="EN-US">Match</span><span style="font-family: 宋体;">函数即可检索出包含关键词的列。</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">详细情况参看</span><span lang="EN-US">MySQL</span><span style="font-family: 宋体;">参考手册关于全文检索的部分。</span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">4.1</span><span style="font-family: 宋体;">使用索引</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">我们首先讨论索引，因为它是加快查询的最重要的工具。还有其他加快查询的技术，但是最有效的莫过于恰当地使用索引了。在</span><span lang="EN-US">MySQL</span><span style="font-family: 宋体;">的邮件清单上，人们通常询问关于使查询更快的问题。在大量的案例中，都是因为表上没有索引，一般只要加上索引就可以立即解决问题。但这样也并非总是有效，因为优化并非总是那样简单。然而，如果不使用索引，在许多情形下，用其他手段改善性能只会是浪费时间。应该首先考虑使用索引取得最大的性能改善，然后再寻求其他可能有帮助的技术。</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">本节介绍索引是什么、它怎样改善查询性能、索引在什么情况下可能会降低性能，以及怎样为表选择索引。下一节，我们将讨论</span><span lang="EN-US">MySQL</span><span style="font-family: 宋体;">的查询优化程序。除了知道怎样创建索引外，了解一些优化程序的知识也是有好处的，因为这样可以更好地利用所创建的索引。某些编写查询的方法实际上会妨碍索引的效果，应该避免这种情况出现。（虽然并非总会这样。有时也会希望忽略优化程序的作用。我们也将介绍这些情况。）</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>4.1.1</span><span style="font-family: 宋体;">索引的益处</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">让我们从一个无索引的表着手来考察索引是怎样起作用的。无索引的表就是一个无序的行集。例如，图</span><span lang="EN-US">4 - 1</span><span style="font-family: 宋体;">给出了我们在第</span><span lang="EN-US">1</span><span style="font-family: 宋体;">章&#8220;</span><span lang="EN-US">MySQL</span><span style="font-family: 宋体;">与</span><span lang="EN-US">SQL </span><span style="font-family: 宋体;">介绍&#8221;</span> <span style="font-family: 宋体;">中首先看到的</span><span lang="EN-US">ad </span><span style="font-family: 宋体;">表。这个表上没有索引，因此如果我们查找某个特定公司的行时，必须查看表中的每一行，看它是否与所需的值匹配。这是一个全表扫描，很慢，如果表中只有少数几个记录与搜索条件相匹配，则其效率是相当低的。</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-family: 'Times New Roman'; font-size: 10.5pt;" lang="EN-US"><v:shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600">&nbsp;<img alt="" src="http://www.blogjava.net/images/blogjava_net/persister/ad.JPG" width="285" border="0" height="289" /><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype></span></span><v:shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype></span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">图</span><span lang="EN-US">4 - 2</span><span style="font-family: 宋体;">给出了相同的表，但在表的</span><span lang="EN-US">company_num </span><span style="font-family: 宋体;">列上增加了一个索引。此索引包含表中每行的一项，但此索引是在</span><span lang="EN-US">company_num </span><span style="font-family: 宋体;">上排序的。现在，不需要逐行搜索全表查找匹配的条款，而是可以利用索引进行查找。假如我们要查找公司</span><span lang="EN-US">13</span><span style="font-family: 宋体;">的所有行，那么可以扫描索引，结果得出</span><span lang="EN-US">3</span><span style="font-family: 宋体;">行。然后到达公司</span><span lang="EN-US">14</span><span style="font-family: 宋体;">的行，这是一个比我们正在查找的要大的号码。索引值是排序的，因此在读到包含</span><span lang="EN-US">14</span><span style="font-family: 宋体;">的记录时，我们知道不会再有匹配的记录，可以退出了。如果查找一个值，它在索引表中某个中间点以前不会出现，那么也有找到其第一个匹配索引项的定位算法，而不用进行表的顺序扫描（如二分查找法）。这样，可以快速定位到第一个匹配的值，以节省大量搜索时间。数据库利用了各种各样的快速定位索引值的技术，这些技术是什么并不重要，重要的是它们工作正常，索引技术是个好东西。</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">有人会问，为什么不只对数据文件进行排序，省掉索引文件？这样不也在搜索时产生相同的效果吗？问得好，如果只有单个索引时，</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">是这样的。不过有可能会用到第二个索引，但同时以两种不同的方法对同一个数据文件进行排序是不可能的。（如，想要一个顾客名的索</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">引，同时又要一个顾客</span><span lang="EN-US">ID </span><span style="font-family: 宋体;">号或电话号码的索引。）将索引文件作为一个与数据文件独立的实体就解决了这个问题，而且允许创建多个索</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">引。此外，索引中的行一般要比数据文件中的行短。在插入或删除值时，为保持排序顺序而移动较短的索引值与移动较长的数据行相比更</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">为容易。</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <img alt="" src="http://www.blogjava.net/images/blogjava_net/persister/ade.JPG" border="0" /></span></span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">这个例子与</span><span lang="EN-US">MySQL</span><span style="font-family: 宋体;">索引表的方法相符。表的数据行保存在数据文件中，而索引值保存在索引文件中。一个表上可有不止一个索引；如果确实有不止一个索引，它们都保存在同一个索引文件中。索引文件中的每个索引由排过序的用来快速访问数据文件的键记录数组构成。</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">前面的讨论描述了单表查询中索引的好处，其中使用索引消除了全表扫描，极大地加快了搜索的速度。在执行涉及多个表的连接查询时，索引甚至会更有价值。在单个表的查询中，每列需要查看的值的数目就是表中行的数目。而在多个表的查询中，可能的组合数目极大，因为这个数目为各表中行数之积。</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp; </span></span><span style="font-family: 宋体;">　</span> <span style="font-family: 宋体;">假如有三个未索引的表</span><span lang="EN-US">t 1</span><span style="font-family: 宋体;">、</span><span lang="EN-US">t 2</span><span style="font-family: 宋体;">、</span><span lang="EN-US">t 3</span><span style="font-family: 宋体;">，分别只包含列</span><span lang="EN-US">c 1</span><span style="font-family: 宋体;">、</span><span lang="EN-US">c 2</span><span style="font-family: 宋体;">、</span><span lang="EN-US">c 3</span><span style="font-family: 宋体;">，每个表分别由含有数值</span><span lang="EN-US">1</span><span style="font-family: 宋体;">到</span><span lang="EN-US">1000 </span><span style="font-family: 宋体;">的</span><span lang="EN-US">1000 </span><span style="font-family: 宋体;">行组成。查找对应值相等的表行组合的查询如下所示：</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>SELECT c1,c2,c3</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>FROM t1,t2,t3</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>WHERE c1=c2 AND c1=c3</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">此查询的结果应该为</span><span lang="EN-US">1000 </span><span style="font-family: 宋体;">行，每个组合包含</span><span lang="EN-US">3 </span><span style="font-family: 宋体;">个相等的值。如果我们在无索引的情况下处理此查询，则不可能知道哪些行包含那些值。因此，必须寻找出所有组合以便得出与</span><span lang="EN-US">WHERE </span><span style="font-family: 宋体;">子句相配的那些组合。可能的组合数目为</span><span lang="EN-US">10 0 0??0 0 0??0 0 0</span><span style="font-family: 宋体;">（十亿），比匹配数目多一百万倍。很多工作都浪费了，并且这个查询将会非常慢，即使在如像</span><span lang="EN-US">MySQL</span><span style="font-family: 宋体;">这样快的数据库中执行也会很慢。而这还是每个表中只有</span><span lang="EN-US">1000 </span><span style="font-family: 宋体;">行的情形。如果每个表中有一百万行时，将会怎样？很显然，这样将会产生性能极为低下的结果。如果对每个表进行索引，就能极大地加速查询进程，因为利用索引的查询处理如下：</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>1) </span><span style="font-family: 宋体;">如下从表</span><span lang="EN-US">t1</span><span style="font-family: 宋体;">中选择第一行，查看此行所包含的值。</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>2) </span><span style="font-family: 宋体;">使用表</span><span lang="EN-US">t2 </span><span style="font-family: 宋体;">上的索引，直接跳到</span><span lang="EN-US">t2 </span><span style="font-family: 宋体;">中与来自</span><span lang="EN-US">t1</span><span style="font-family: 宋体;">的值匹配的行。类似，利用表</span><span lang="EN-US">t3 </span><span style="font-family: 宋体;">上的索引，直接跳到</span><span lang="EN-US">t3 </span><span style="font-family: 宋体;">中与来自</span><span lang="EN-US">t1</span><span style="font-family: 宋体;">的值匹配的行。</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>3) </span><span style="font-family: 宋体;">进到表</span><span lang="EN-US">t1</span><span style="font-family: 宋体;">的下一行并重复前面的过程直到</span><span lang="EN-US">t1</span><span style="font-family: 宋体;">中所有的行已经查过。在此情形下，我们仍然对表</span><span lang="EN-US">t1</span><span style="font-family: 宋体;">执行了一个完全扫描，但能够在表</span><span lang="EN-US">t2 </span><span style="font-family: 宋体;">和</span><span lang="EN-US">t3 </span><span style="font-family: 宋体;">上进行索引查找直接取出这些表中的行。从道理上说，这时的查询比未用索引时要快一百万倍。如上所述，</span><span lang="EN-US">MySQL</span><span style="font-family: 宋体;">利用索引加速了</span><span lang="EN-US">WHERE </span><span style="font-family: 宋体;">子句中与条件相配的行的搜索，或者说在执行连接时加快了与其他表中的行匹配的行的搜索。它也利用索引来改进其他操作的性能：</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">■</span> <span style="font-family: 宋体;">在使用</span><span lang="EN-US">MIN( ) </span><span style="font-family: 宋体;">和</span><span lang="EN-US">MAX( ) </span><span style="font-family: 宋体;">函数时，能够快速找到索引列的最小或最大值。</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">■</span><span lang="EN-US"> MySQL</span><span style="font-family: 宋体;">常常能够利用索引来完成</span><span lang="EN-US">ORDER BY </span><span style="font-family: 宋体;">子句的排序操作。</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">■</span> <span style="font-family: 宋体;">有时，</span><span lang="EN-US">MySQL</span><span style="font-family: 宋体;">可避免对整个数据文件的读取。假如从一个索引数值列中选择值，而且不选择表中其他列。这时，通过对索引值的读取，就已经得到了读取数据文件所要得到的值。没有对相同的值进行两次读取的必要，因此，甚至无需涉及数据文件。</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>4.1.2 </span><span style="font-family: 宋体;">索引的弊端</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">一般情况下，如果</span><span lang="EN-US">MySQL</span><span style="font-family: 宋体;">能够知道怎样用索引来更快地处理查询，它就会这样做。这表示，在大多数情况下，如果您不对表进行索引，则损害的是您自己的利益。可以看出，作者描绘了索引的诸多好处。但有不利之处吗？是的，有。实际上，这些缺点被优点所掩盖了，</span></p>
<p class="MsoNormal"><span style="font-family: 宋体;">但应该对它们有所了解。</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">首先，索引文件要占磁盘空间。如果有大量的索引，索引文件可能会比数据文件更快地达到最大的文件尺寸。其次，索引文件加快了检索，但增加了插入和删除，以及更新索引列中的值的时间（即，降低了大多数涉及写入的操作的时间），因为写操作不仅涉及数据行，而且还常常涉及索引。一个表拥有的索引越多，则写操作的平均性能下降就越大。在</span><span lang="EN-US">4 . 4</span><span style="font-family: 宋体;">节&#8220;有效地装载数据&#8221;中，我们将更为详细地介绍这些性能问题，并讨论怎样解决。</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>4.1.3 </span><span style="font-family: 宋体;">选择索引</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">创建索引的语法已经在</span><span lang="EN-US">3 . 4 . 3</span><span style="font-family: 宋体;">节&#8220;创建和删除索引&#8221;中进行了介绍。这里，我们假定您已经阅读过该节。但是知道语法并不能帮助确定表怎样进行索引。要决定表怎样进行索引需要考虑表的使用方式。本节介绍一些关于怎样确定和挑选索引列的准则：</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">■</span> <span style="font-family: 宋体;">搜索的索引列，不一定是所要选择的列。换句话说，最适合索引的列是出现在</span><span lang="EN-US">WHERE </span><span style="font-family: 宋体;">子句中的列，或连接子句中指定的列，而不是出现在</span><span lang="EN-US">SELECT </span><span style="font-family: 宋体;">关键字后的选择列表中的列：</span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">当然，所选择的列和用于</span><span lang="EN-US">WHERE </span><span style="font-family: 宋体;">子句的列也可能是相同的。关键是，列出现在选择列表中不是该列应该索引的标志。出现在连接子句中的列或出现在形如</span><span lang="EN-US">col1= col2 </span><span style="font-family: 宋体;">的表达式中的列是很适合索引的列。查询中的</span><span lang="EN-US">col_b </span><span style="font-family: 宋体;">和</span><span lang="EN-US">col_c </span><span style="font-family: 宋体;">就是这样的例子。如果</span><span lang="EN-US">MySQL</span><span style="font-family: 宋体;">能利用连接列来优化一个查询，表示它通过消除全表扫描相当可观地减少了表行的组合。</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">■</span> <span style="font-family: 宋体;">使用惟一索引。考虑某列中值的分布。对于惟一值的列，索引的效果最好，而具有多个重复值的列，其索引效果最差。例如，存放年龄的列具有不同值，很容易区分各行。而用来记录性别的列，只含有&#8220;</span><span lang="EN-US"> M</span><span style="font-family: 宋体;">&#8221;和&#8220;</span><span lang="EN-US">F</span><span style="font-family: 宋体;">&#8221;，则对此列进行索引没有多大用处（不管搜索哪个值，都会得出大约一半的行）。</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">■</span> <span style="font-family: 宋体;">使用短索引。如果对串列进行索引，应该指定一个前缀长度，只要有可能就应该这样做。例如，如果有一个</span><span lang="EN-US">CHAR(200) </span><span style="font-family: 宋体;">列，如果在前</span><span lang="EN-US">10 </span><span style="font-family: 宋体;">个或</span><span lang="EN-US">20 </span><span style="font-family: 宋体;">个字符内，多数值是惟一的，那么就不要对整个列进行索引。对前</span><span lang="EN-US">10 </span><span style="font-family: 宋体;">个或</span><span lang="EN-US">20 </span><span style="font-family: 宋体;">个字符进行索引能够节省大量索引空间，也可能会使查询更快。较小的索引涉及的磁盘</span><span lang="EN-US">I/O </span><span style="font-family: 宋体;">较少，较短的值比较起来更快。更为重要的是，对于较短的键值，索引高速缓存中的块能容纳更多的键值，因此，</span><span lang="EN-US">MySQL</span><span style="font-family: 宋体;">也可以在内存中容纳更多的值。这增加了找到行而不用读取索引中较多块的可能性。（当然，应该利用一些常识。如仅用列值的第一个字符进行索引是不可能有多大好处的，因为这个索引中不会有许多不同的值。）</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">■</span> <span style="font-family: 宋体;">利用最左前缀。在创建一个</span><span lang="EN-US">n </span><span style="font-family: 宋体;">列的索引时，实际是创建了</span><span lang="EN-US">MySQL</span><span style="font-family: 宋体;">可利用的</span><span lang="EN-US">n </span><span style="font-family: 宋体;">个索引。多列索引可起几个索引的作用，因为可利用索引中最左边的列集来匹配行。这样的列集称为最左前缀。（这与索引一个列的前缀不同，索引一个列的前缀是利用该的前</span><span lang="EN-US">n </span><span style="font-family: 宋体;">个字符作为索引值。）</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: 宋体;">假如一个表在分别名为</span><span lang="EN-US">s t a t e</span><span style="font-family: 宋体;">、</span><span lang="EN-US">city </span><span style="font-family: 宋体;">和</span><span lang="EN-US">zip </span><span style="font-family: 宋体;">的三个列上有一个索引。索引中的行是按</span><span lang="EN-US">state/city/zip </span><span style="font-family: 宋体;">的次序存放的，因此，索引中的行也会自动按</span><span lang="EN-US">state/city </span><span style="font-family: 宋体;">的顺序和</span><span lang="EN-US">state </span><span style="font-family: 宋体;">的顺序存放。这表示，即使在查询中只指定</span><span lang="EN-US">state </span><span style="font-family: 宋体;">值或只指定</span><span lang="EN-US">state </span><span style="font-family: 宋体;">和</span><span lang="EN-US">city </span><span style="font-family: 宋体;">的值，</span><span lang="EN-US">MySQL</span><span style="font-family: 宋体;">也可以利用索引。因此，此索引可用来搜索下列的列组合：</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>state,city,zip</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>state,city</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>sate</span></p>
<p class="MsoNormal"><span lang="EN-US"><span>&nbsp;&nbsp;&nbsp; </span>MySQL</span><span style="font-family: 宋体;">不能使用不涉及左前缀的搜索。例如，如果按</span><span lang="EN-US">city </span><span style="font-family: 宋体;">或</span><span lang="EN-US">zip </span><span style="font-family: 宋体;">进行搜索，则不能使用该索引。如果要搜索某个州以及某个</span><span lang="EN-US">zip </span><span style="font-family: 宋体;">代码（索引中的列</span><span lang="EN-US">1</span><span style="font-family: 宋体;">和列</span><span lang="EN-US">3</span><span style="font-family: 宋体;">），则此索引不能用于相应值的组合。但是，可利用索引来寻找与该州相符的行，以减少搜索范围。</span></p>
<img alt="" src="http://www.blogjava.net/images/blogjava_net/persister/ad.JPG" border="0" />
<img src ="http://www.blogjava.net/persister/aggbug/291923.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-08-20 11:37 <a href="http://www.blogjava.net/persister/archive/2009/08/20/291923.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MySQL Got a packet bigger than 'max_allowed_packet' bytes错误</title><link>http://www.blogjava.net/persister/archive/2009/07/30/289186.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Thu, 30 Jul 2009 14:54:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/07/30/289186.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/289186.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/07/30/289186.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/289186.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/289186.html</trackback:ping><description><![CDATA[今天用SQLYog执行数据插入命令，一共3万多条记录吧，导入数据库时提示：<br />
<br />
Error Code:1153 Got a packet bigger than 'max_allowed_packet' bytes错误提示。<br />
开始没注意，提示一大堆，后来才看见这句<br />
使用SQLyog工具导出MySQL数据时，当数据量大时，导出不会错误，但导入时会出现错误。如果将SQL单独执行会发现是Error Code:1153 Got a packet bigger than 'max_allowed_packet' bytes错误。<br />
对于这个问题可以在my.ini中最后增加一行max_allowed_packet=16M即可（根据实际情况设置）。<br />
<br />
注意，在[client]和[mysql]部分增加无效，那个是客户端读取的参数。
<img src ="http://www.blogjava.net/persister/aggbug/289186.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-07-30 22:54 <a href="http://www.blogjava.net/persister/archive/2009/07/30/289186.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>mysql repair命令</title><link>http://www.blogjava.net/persister/archive/2009/04/23/267192.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Thu, 23 Apr 2009 09:30:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2009/04/23/267192.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/267192.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2009/04/23/267192.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/267192.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/267192.html</trackback:ping><description><![CDATA[今天在测试的时候，系统无法登入。报如下错误：<br />
<br />
SequenceUtil.SequenceBank.fillBank] SQL Exception while executing the following:<br />
UPDATE SEQUENCE_VALUE_ITEM SET SEQ_ID=SEQ_ID+100 WHERE SEQ_NAME='Visit'<br />
Error was:Incorrect key file for table './ccbofbiz/sequence_value_item.MYI'; try to repair it<br />
Exception: java.sql.SQLException<br />
Message: Incorrect key file for table './ccbofbiz/sequence_value_item.MYI'; try to repair it<br />
<br />
很少看到这样的错误，今天被我碰到了，哈哈<br />
运行如下命令：<br />
repair table SEQUENCE_VALUE_ITEM<br />
<br />
成功了，非常行不错。
<img src ="http://www.blogjava.net/persister/aggbug/267192.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2009-04-23 17:30 <a href="http://www.blogjava.net/persister/archive/2009/04/23/267192.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>从LiveJournal后台发展看大规模网站性能优化方法(无图片版)</title><link>http://www.blogjava.net/persister/archive/2008/12/05/244515.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Fri, 05 Dec 2008 02:52:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2008/12/05/244515.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/244515.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2008/12/05/244515.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/244515.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/244515.html</trackback:ping><description><![CDATA[<h3>此为转载，原文请自行搜索。</h3>
<h2>一、LiveJournal发展历程</h2>
<a href="http://www.livejournal.com/">LiveJournal</a>是99年始于校园中的项目，几个人出于爱好做了这样一个应用，以实现以下功能：
<ul>
    <li>博客，论坛
    </li>
    <li>社会性网络，找到朋友
    </li>
    <li>聚合，把朋友的文章聚合在一起</li>
</ul>
LiveJournal采用了大量的开源软件，甚至它本身也是一个开源软件。
<p>在上线后，LiveJournal实现了非常快速的增长：</p>
<ul>
    <li>2004年4月份：280万注册用户。
    </li>
    <li>2005年4月份：680万注册用户。
    </li>
    <li>2005年8月份：790万注册用户。
    </li>
    <li>达到了每秒钟上千次的页面请求及处理。
    </li>
    <li>使用了大量MySQL服务器。
    </li>
    <li>使用了大量通用组件。</li>
</ul>
<h2>二、LiveJournal架构现状概况</h2>
<p><br />
<br />
</p>
<h2>三、从LiveJournal发展中学习</h2>
<p>&nbsp;</p>
<p>LiveJournal从1台服务器发展到100台服务器，这其中经历了无数的伤痛，但同时也摸索出了解决这些问题的方法，通过对LiveJournal的学习，可以让我们避免LJ曾经犯过的错误，并且从一开始就对系统进行良好的设计，以避免后期的痛苦。</p>
<p>下面我们一步一步看LJ发展的脚步。</p>
<div id="a000073more">
<div id="more">
<h2>1、一台服务器</h2>
<p>一台别人捐助的服务器，LJ最初就跑在上面，就像Google开始时候用的破服务器一样，值得我们尊敬。这个阶段，LJ的人以惊人的速度熟悉的Unix的操作管理，服务器性能出现过问题，不过还好，可以通过一些小修小改应付过去。在这个阶段里LJ把CGI升级到了FastCGI。</p>
<p>最终问题出现了，网站越来越慢，已经无法通过优过化来解决的地步，需要更多的服务器，这时LJ开始提供付费服务，可能是想通过这些钱来购买新的服务器，以解决当时的困境。<br />
毫无疑问，当时LJ存在巨大的单点问题，所有的东西都在那台服务器的铁皮盒子里装着。</p>
<p><br />
</p>
<h2>2、两台服务器</h2>
<p>用付费服务赚来的钱LJ买了两台服务器：一台叫做Kenny的Dell 6U机器用于提供Web服务，一台叫做Cartman的Dell 6U服务器用于提供数据库服务。</p>
<p><br />
</p>
<p>LJ有了更大的磁盘，更多的计算资源。但同时网络结构还是非常简单，每台机器两块网卡，Cartman通过内网为Kenny提供MySQL数据库服务。<br />
<br />
暂时解决了负载的问题，新的问题又出现了：</p>
<ul>
    <li>原来的一个单点变成了两个单点。
    </li>
    <li>没有冷备份或热备份。
    </li>
    <li>网站速度慢的问题又开始出现了，没办法，增长太快了。
    </li>
    <li>Web服务器上CPU达到上限，需要更多的Web服务器。</li>
</ul>
<h2>3、四台服务器</h2>
<p>又买了两台，Kyle和Stan，这次都是1U的，都用于提供Web服务。目前LJ一共有3台Web服务器和一台数据库服务器。这时需要在3台Web服务器上进行负载均横。</p>
<p><br />
</p>
<p>LJ把Kenny用于外部的网关，使用<a href="http://www.backhand.org/mod_backhand/">mod_backhand</a>进行负载均横。</p>
<p>然后问题又出现了：</p>
<ul>
    <li>单点故障。数据库和用于做网关的Web服务器都是单点，一旦任何一台机器出现问题将导致所有服务不可用。虽然用于做网关的Web服务器可以通过保持心跳同步迅速切换，但还是无法解决数据库的单点，LJ当时也没做这个。
    </li>
    <li>网站又变慢了，这次是因为IO和数据库的问题，问题是怎么往应用里面添加数据库呢？</li>
</ul>
<h2>4、五台服务器</h2>
<p>又买了一台数据库服务器。在两台数据库服务器上使用了数据库同步(Mysql支持的Master-Slave模式)，写操作全部针对主数据库（通过Binlog，主服务器上的写操作可以迅速同步到从服务器上），读操作在两个数据库上同时进行(也算是负载均横的一种吧)。</p>
<p><br />
</p>
<p>实现同步时要注意几个事项：</p>
<ul>
    <li>读操作数据库选择算法处理，要选一个当前负载轻一点的数据库。
    </li>
    <li>在从数据库服务器上只能进行读操作
    </li>
    <li>准备好应对同步过程中的延迟，处理不好可能会导致数据库同步的中断。只需要对写操作进行判断即可，读操作不存在同步问题。</li>
</ul>
<h2>5、更多服务器</h2>
<p>有钱了，当然要多买些服务器。部署后快了没多久，又开始慢了。这次有更多的Web服务器，更多的数据库服务器，存在 IO与CPU争用。于是采用了BIG-IP作为负载均衡解决方案。</p>
<p><br />
</p>
<h2>6、现在我们在哪里：</h2>
<p><br />
</p>
<p>现在服务器基本上够了，但性能还是有问题，原因出在架构上。</p>
<p>数据库的架构是最大的问题。由于增加的数据库都是以Slave模式添加到应用内，这样唯一的好处就是将读操作分布到了多台机器，但这样带来的后果就是写操作被大量分发，每台机器都要执行，服务器越多，浪费就越大，随着写操作的增加，用于服务读操作的资源越来越少。</p>
<p><br />
</p>
<p>由一台分布到两台</p>
<p><br />
</p>
<p>最终效果</p>
<p>现在我们发现，我们并不需要把这些数据在如此多的服务器上都保留一份。服务器上已经做了RAID，数据库也进行了备份，这么多的备份完全是对资源的浪费，属于冗余极端过度。那为什么不把数据分布存储呢？</p>
<p>问题发现了，开始考虑如何解决。现在要做的就是把不同用户的数据分布到不同的服务器上进行存储，以实现数据的分布式存储，让每台机器只为相对固定的用户服务，以实现平行的架构和良好的可扩展性。</p>
<p>为了实现用户分组，我们需要为每一个用户分配一个组标记，用于标记此用户的数据存放在哪一组数据库服务器中。每组数据库由一个master及几个slave组成，并且slave的数量在2-3台，以实现系统资源的最合理分配，既保证数据读操作分布，又避免数据过度冗余以及同步操作对系统资源的过度消耗。</p>
<p><br />
</p>
<p>由一台（一组）中心服务器提供用户分组控制。所有用户的分组信息都存储在这台机器上，所有针对用户的操作需要先查询这台机器得到用户的组号，然后再到相应的数据库组中获取数据。</p>
<p>这样的用户架构与目前LJ的架构已经很相像了。</p>
<p>在具体的实现时需要注意几个问题：</p>
<ul>
    <li>在数据库组内不要使用自增ID，以便于以后在数据库组之间迁移用户，以实现更合理的I/O，磁盘空间及负载分布。
    </li>
    <li>将userid，postid存储在全局服务器上，可以使用自增，数据库组中的相应值必须以全局服务器上的值为准。全局服务器上使用事务型数据库InnoDB。
    </li>
    <li>在数据库组之间迁移用户时要万分小心，当迁移时用户不能有写操作。</li>
</ul>
<h2>7、现在我们在哪里</h2>
<p><br />
</p>
<p>问题：</p>
<ul>
    <li>一个全局主服务器，挂掉的话所有用户注册及写操作就挂掉。
    </li>
    <li>每个数据库组一个主服务器，挂掉的话这组用户的写操作就挂掉。
    </li>
    <li>数据库组从服务器挂掉的话会导致其它服务器负载过大。</li>
</ul>
<p>对于Master-Slave模式的单点问题，LJ采取了Master-Master模式来解决。所谓Master-Master实际上是人工实现的，并不是由MySQL直接提供的，实际上也就是两台机器同时是Master，也同时是Slave，互相同步。</p>
<p>Master-Master实现时需要注意：</p>
<ul>
    <li>一个Master出错后恢复同步，最好由服务器自动完成。
    </li>
    <li>数字分配，由于同时在两台机器上写，有些ID可能会冲突。</li>
</ul>
<p>解决方案：<br />
</p>
<ul>
    <li>奇偶数分配ID，一台机器上写奇数，一台机器上写偶数
    </li>
    <li>通过全局服务器进行分配(LJ采用的做法)。</li>
</ul>
<p>&nbsp;</p>
<p>Master-Master模式还有一种用法，这种方法与前一种相比，仍然保持两台机器的同步，但只有一台机器提供服务（读和写），在每天晚上的时候进行轮换，或者出现问题的时候进行切换。</p>
<h2>8、现在我们在哪里</h2>
<p><br />
</p>
<p>现在插播一条广告，MyISAM VS InnoDB。</p>
<p>使用InnoDB：</p>
<ul>
    <li>支持事务
    </li>
    <li>需要做更多的配置，不过值得，可以更安全的存储数据，以及得到更快的速度。</li>
</ul>
<p>使用MyISAM：</p>
<ul>
    <li>记录日志（LJ用它来记网络访问日志）
    </li>
    <li>存储只读静态数据，足够快。
    </li>
    <li>并发性很差，无法同时读写数据（添加数据可以）
    </li>
    <li>MySQL非正常关闭或死机时会导致索引错误，需要使用myisamchk修复，而且当访问量大时出现非常频繁。</li>
</ul>
<h2>9、缓存</h2>
<p>去年我写过<a href="http://www.example.net.cn/archives/2006/01/eoamemcachedoea.html">一篇文章介绍memcached</a>，它就是由LJ的团队开发的一款缓存工具，以key-value的方式将数据存储到分布的内存中。LJ缓存的数据：</p>
<ul>
    <li>12台独立服务器（不是捐赠的）
    </li>
    <li>28个实例
    </li>
    <li>30GB总容量
    </li>
    <li>90-93%的命中率（用过squid的人可能知道，squid内存加磁盘的命中率大概在70-80%）</li>
</ul>
<p>如何建立缓存策略？</p>
<p>想缓存所有的东西？那是不可能的，我们只需要缓存已经或者可能导致系统瓶颈的地方，最大程度的提交系统运行效率。通过对MySQL的日志的分析我们可以找到缓存的对象。</p>
<p>缓存的缺点？</p>
<ul>
    <li>没有完美的事物，缓存也有缺点：
    </li>
    <li>增大开发量，需要针对缓存处理编写特殊的代码。
    </li>
    <li>管理难度增加，需要更多人参与系统维护。
    </li>
    <li>当然大内存也需要钱。</li>
</ul>
<h2>10、Web访问负载均衡</h2>
<p>在数据包级别使用BIG-IP，但BIG-IP并不知道我们内部的处理机制，无法判断由哪台服务器对这些请求进行处理。反向代理并不能很好的起到作用，不是已经够快了，就是达不到我们想要的效果。</p>
<p>所以，LJ又开发了<a href="http://www.danga.com/perlbal/">Perlbal</a>。特点：</p>
<ul>
    <li>快，小，可管理的http web 服务器/代理
    </li>
    <li>可以在内部进行转发
    </li>
    <li>使用Perl开发
    </li>
    <li>单线程，异步，基于事件，使用epoll , kqueue
    </li>
    <li>支持Console管理与http远程管理，支持动态配置加载
    </li>
    <li>多种模式：web服务器，反向代理，插件
    </li>
    <li>支持插件：GIF/PNG互换？</li>
</ul>
<h2>11、MogileFS</h2>
<p>LJ使用开源的<a href="http://www.danga.com/mogilefs/">MogileFS</a>作为分布式文件存储系统。MogileFS使用非常简单，它的主要设计思想是：</p>
<ul>
    <li>文件属于类（类是最小的复制单位）
    </li>
    <li>跟踪文件存储位置
    </li>
    <li>在不同主机上存储
    </li>
    <li>使用MySQL集群统一存储分布信息
    </li>
    <li>大容易廉价磁盘</li>
</ul>
<p>到目前为止就这么多了，更多文档可以在<a href="http://www.danga.com/words/">http://www.danga.com/words/</a>找到。<a href="http://www.danga.com/">Danga.com</a>和<a href="http://www.livejournal.com/">LiveJournal.com</a>的同学们拿这个文档参加了两次MySQL Con，两次OS Con，以及众多的其它会议，无私的把他们的经验分享出来，值得我们学习。在web2.0时代快速开发得到大家越来越多的重视，但良好的设计仍是每一个应用的基础，希望web2.0们在成长为Top500网站的路上，不要因为架构阻碍了网站的发展。</p>
<p>参考资料：<a href="http://www.danga.com/words/2005_oscon/oscon-2005.pdf">http://www.danga.com/words/2005_oscon/oscon-2005.pdf</a></p>
</div>
</div>
<img src ="http://www.blogjava.net/persister/aggbug/244515.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2008-12-05 10:52 <a href="http://www.blogjava.net/persister/archive/2008/12/05/244515.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>对mysql explain讲的比较清楚的</title><link>http://www.blogjava.net/persister/archive/2008/10/27/236813.html</link><dc:creator>persister</dc:creator><author>persister</author><pubDate>Mon, 27 Oct 2008 02:40:00 GMT</pubDate><guid>http://www.blogjava.net/persister/archive/2008/10/27/236813.html</guid><wfw:comment>http://www.blogjava.net/persister/comments/236813.html</wfw:comment><comments>http://www.blogjava.net/persister/archive/2008/10/27/236813.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/persister/comments/commentRss/236813.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/persister/services/trackbacks/236813.html</trackback:ping><description><![CDATA[在 explain的帮助下，您就知道什么时候该给表添加索引，以使用索引来查找记录从而让select 运行更快。<br />
如果由于不恰当使用索引而引起一些问题的话，可以运行 analyze table来更新该表的统计信息，例如键的基数，它能帮您在优化方面做出更好的选择。<br />
<br />
explain 返回了一行记录，它包括了
select语句中用到的各个表的信息。这些表在结果中按照mysql即将执行的查询中读取的顺序列出来。mysql用一次扫描多次连接（single-
sweep,multi-join）的方法来解决连接。这意味着mysql从第一个表中读取一条记录，然后在第二个表中查找到对应的记录，然后在第三个表
中查找，依次类推。当所有的表都扫描完了，它输出选择的字段并且回溯所有的表，直到找不到为止，因为有的表中可能有多条匹配的记录下一条记录将从该表读
取，再从下一个表开始继续处理。<br />
在mysql version 4.1中，explain输出的结果格式改变了，使得它更适合例如 union语句、子查询以及派生表的结构。更令人注意的是，它新增了2个字段： id和 select_type。当你使用早于mysql4.1的版本就看不到这些字段了。<br />
explain结果的每行记录显示了每个表的相关信息，每行记录都包含以下几个字段：<br />
<br />
id <br />
本次 select 的标识符。在查询中每个 select都有一个顺序的数值。<br />
select_type <br />
select 的类型，可能会有以下几种：<br />
simple: 简单的 select （没有使用 union或子查询）<br />
<br />
primary: 最外层的 select。<br />
<br />
union: 第二层，在select 之后使用了 union。<br />
<br />
dependent union: union 语句中的第二个select，依赖于外部子查询<br />
<br />
subquery: 子查询中的第一个 select<br />
<br />
dependent subquery: 子查询中的第一个 subquery依赖于外部的子查询<br />
<br />
derived: 派生表 select（from子句中的子查询）<br />
<br />
table<br />
记录查询引用的表。<br />
<br />
type<br />
表连接类型。以下列出了各种不同类型的表连接，依次是从最好的到最差的：<br />
<br />
system:表只有一行记录（等于系统表）。这是 const表连接类型的一个特例。<br />
<br />
const:表中最多只有一行匹配的记录，它在查询一开始的时候就会被读取出来。由于只有一行记录，在余下的优化程序里该行记录的字段值可以被当作是一个
恒定值。const表查询起来非常快，因为只要读取一次！const 用于在和 primary key 或unique
索引中有固定值比较的情形。下面的几个查询中，tbl_name 就是 c表了：<br />
select * from tbl_name where primary_key=1; select * from tbl_namewhere primary_key_part1=1 and primary_key_part2=2;<br />
<br />
eq_ref:从该表中会有一行记录被读取出来以和从前一个表中读取出来的记录做联合。与const类型不同的是，这是最好的连接类型。它用在索引所有部
分都用于做连接并且这个索引是一个primary key 或 unique
类型。eq_ref可以用于在进行"="做比较时检索字段。比较的值可以是固定值或者是表达式，表达示中可以使用表里的字段，它们在读表之前已经准备好
了。以下的几个例子中，mysql使用了eq_ref 连接来处理 ref_table：<br />
<br />
<br />
select * from ref_table,other_table
whereref_table.key_column=other_table.column; select *
fromref_table,other_table
whereref_table.key_column_part1=other_table.column
andref_table.key_column_part2=1;<br />
<br />
ref: 该表中所有符合检索值的记录都会被取出来和从上一个表中取出来的记录作联合。ref用于连接程序使用键的最左前缀或者是该键不是
primary key 或
unique索引（换句话说，就是连接程序无法根据键值只取得一条记录）的情况。当根据键值只查询到少数几条匹配的记录时，这就是一个不错的连接类型。
ref还可以用于检索字段使用 =操作符来比较的时候。以下的几个例子中，mysql将使用 ref 来处理ref_table：<br />
select * from ref_table where key_column=expr; select *
fromref_table,other_table whereref_table.key_column=other_table.column;
select * fromref_table,other_table
whereref_table.key_column_part1=other_table.column
andref_table.key_column_part2=1;<br />
<br />
ref_or_null: 这种连接类型类似 ref，不同的是mysql会在检索的时候额外的搜索包含null
值的记录。这种连接类型的优化是从mysql4.1.1开始的，它经常用于子查询。在以下的例子中，mysql使用ref_or_null 类型来处理
ref_table：<br />
select * from ref_table where key_column=expr or key_column is null;<br />
<br />
<br />
unique_subquery: 这种类型用例如一下形式的 in 子查询来替换 ref：<br />
value in (select primary_key from single_table where some_expr)<br />
<br />
unique_subquery: 只是用来完全替换子查询的索引查找函数效率更高了。<br />
<br />
index_subquery: 这种连接类型类似 unique_subquery。它用子查询来代替in，不过它用于在子查询中没有唯一索引的情况下，例如以下形式：<br />
value in (select key_column from single_table where some_expr)<br />
<br />
range:
只有在给定范围的记录才会被取出来，利用索引来取得一条记录。key字段表示使用了哪个索引。key_len字段包括了使用的键的最长部分。这种类型时
ref 字段值是 null。range用于将某个字段和一个定植用以下任何操作符比较时 =, &lt;&gt;, &gt;,&gt;=,
&lt;, &lt;=, is null, &lt;=&gt;, between, 或 in：<br />
select * from tbl_name where key_column = 10; select * fromtbl_name
where key_column between 10 and 20; select * from tbl_namewhere
key_column in (10,20,30); select * from tbl_name wherekey_part1= 10 and
key_part2 in (10,20,30);<br />
<br />
index: 连接类型跟 all 一样，不同的是它只扫描索引树。它通常会比 all快点，因为索引文件通常比数据文件小。mysql在查询的字段知识单独的索引的一部分的情况下使用这种连接类型。<br />
<br />
all: 将对该表做全部扫描以和从前一个表中取得的记录作联合。这时候如果第一个表没有被标识为const的话就不大好了，在其他情况下通常是非常糟糕的。正常地，可以通过增加索引使得能从表中更快的取得记录以避免all。<br />
<br />
<br />
possible_keys<br />
possible_keys字段是指 mysql在搜索表记录时可能使用哪个索引。注意，这个字段完全独立于explain 显示的表顺序。这就意味着
possible_keys里面所包含的索引可能在实际的使用中没用到。如果这个字段的值是null，就表示没有索引被用到。这种情况下，就可以检查
where子句中哪些字段那些字段适合增加索引以提高查询的性能。就这样，创建一下索引，然后再用explain
检查一下。详细的查看章节"14.2.2 alter tablesyntax"。想看表都有什么索引，可以通过 show index from
tbl_name来看。<br />
<br />
&nbsp;<br />
key<br />
key字段显示了mysql实际上要用的索引。当没有任何索引被用到的时候，这个字段的值就是null。想要让mysql强行使用或者忽略在
possible_keys字段中的索引列表，可以在查询语句中使用关键字force index, use index,或 ignore
index。如果是 myisam 和 bdb 类型表，可以使用 analyzetable 来帮助分析使用使用哪个索引更好。如果是
myisam类型表，运行命令 myisamchk --analyze也是一样的效果。详细的可以查看章节"14.5.2.1 analyze
tablesyntax"和"5.7.2 table maintenance and crash recovery"。<br />
<br />
key_len<br />
key_len 字段显示了mysql使用索引的长度。当 key 字段的值为 null时，索引的长度就是 null。注意，key_len的值可以告诉你在联合索引中mysql会真正使用了哪些索引。<br />
<br />
ref<br />
ref 字段显示了哪些字段或者常量被用来和 key配合从表中查询记录出来。<br />
<br />
rows<br />
rows 字段显示了mysql认为在查询中应该检索的记录数。<br />
<br />
extra<br />
<br />
本字段显示了查询中mysql的附加信息。以下是这个字段的几个不同值的解释：<br />
<br />
distinct:mysql当找到当前记录的匹配联合结果的第一条记录之后，就不再搜索其他记录了。<br />
<br />
not exists:mysql在查询时做一个 left join优化时，当它在当前表中找到了和前一条记录符合 left join条件后，就不再搜索更多的记录了。下面是一个这种类型的查询例子：<br />
select * from t1 left join t2 on t1.id=t2.id where t2.id isnull;<br />
<br />
假使 t2.id 定义为 not null。这种情况下，mysql将会扫描表 t1并且用 t1.id 的值在 t2 中查找记录。当在
t2中找到一条匹配的记录时，这就意味着 t2.id 肯定不会都是null，就不会再在 t2 中查找相同 id值的其他记录了。也可以这么说，对于
t1 中的每个记录，mysql只需要在t2 中做一次查找，而不管在 t2 中实际有多少匹配的记录。<br />
<br />
range checked for each record (index map: #)<br />
<br />
mysql没找到合适的可用的索引。取代的办法是，对于前一个表的每一个行连接，它会做一个检验以决定该使用哪个索引（如果有的话），并且使用这个索引来从表里取得记录。这个过程不会很快，但总比没有任何索引时做表连接来得快。<br />
<br />
using filesort: mysql需要额外的做一遍从而以排好的顺序取得记录。排序程序根据连接的类型遍历所有的记录，并且将所有符合
where条件的记录的要排序的键和指向记录的指针存储起来。这些键已经排完序了，对应的记录也会按照排好的顺序取出来。详情请看"7.2.9how
mysql optimizes order by"。<br />
using index<br />
<br />
字段的信息直接从索引树中的信息取得，而不再去扫描实际的记录。这种策略用于查询时的字段是一个独立索引的一部分。<br />
<br />
using temporary: mysql需要创建临时表存储结果以完成查询。这种情况通常发生在查询时包含了groupby 和 order by 子句，它以不同的方式列出了各个字段。<br />
using where<br />
<br />
where子句将用来限制哪些记录匹配了下一个表或者发送给客户端。除非你特别地想要取得或者检查表种的所有记录，否则的话当查询的extra 字段值不是 using where 并且表连接类型是 all 或 index时可能表示有问题。<br />
<br />
<br />
如果你想要让查询尽可能的快，那么就应该注意 extra 字段的值为usingfilesort 和 using temporary 的情况。<br />
<br />
你可以通过 explain 的结果中
rows字段的值的乘积大概地知道本次连接表现如何。它可以粗略地告诉我们mysql在查询过程中会查询多少条记录。如果是使用系统变量
max_join_size 来取得查询结果，这个乘积还可以用来确定会执行哪些多表select 语句。<br />
下面的例子展示了如何通过 explain提供的信息来较大程度地优化多表联合查询的性能。<br />
假设有下面的 select 语句，正打算用 explain 来检测：<br />
explain select tt.ticketnumber, tt.timein,
tt.projectreference,tt.estimatedshipdate, tt.actualshipdate,
tt.clientid,tt.servicecodes, tt.repetitiveid,
tt.currentprocess,tt.currentdppers tt.recordvolume, tt.dpprinted,
et.country,et_1.country, do.custname from tt, et, et as et_1, do
wherett.submittime is null and tt.actualpc = et.employid
andtt.assignedpc = et_1.employid and tt.clientid = do.custnmbr;<br />
<br />
在这个例子中，先做以下假设：<br />
<br />
&nbsp;<br />
<br />
要比较的字段定义如下：<br />
table&nbsp; column&nbsp; columntype <br />
tt&nbsp; actualpc char(10) <br />
tt&nbsp; assignedpc char(10) <br />
tt&nbsp; clientid char(10) <br />
et&nbsp; employid char(15) <br />
do&nbsp; custnmbr char(15) <br />
<br />
<br />
数据表的索引如下：<br />
table&nbsp; index <br />
tt&nbsp; actualpc <br />
tt&nbsp; assignedpc <br />
tt&nbsp; clientid <br />
et&nbsp; employid (primary key) <br />
do&nbsp; custnmbr (primary key) <br />
<br />
<br />
tt.actualpc 的值是不均匀分布的。<br />
<br />
在任何优化措施未采取之前，经过 explain分析的结果显示如下：<br />
table type possible_keys key key_len ref rows extra <br />
et all primarynull null null 74 <br />
do all primary null null null 2135 <br />
et_1 allprimary null null null 74 <br />
tt all assignedpc, null null null 3872 clientid, actualpc range checked for each record (key map: 35)<br />
<br />
由于字段 type
的对于每个表值都是all，这个结果意味着mysql对所有的表做一个迪卡尔积；这就是说，每条记录的组合。这将需要花很长的时间，因为需要扫描每个表总
记录数乘积的总和。在这情况下，它的积是74 * 2135 * 74 * 3872 =
45,268,558,720条记录。如果数据表更大的话，你可以想象一下需要多长的时间。<br />
在这里有个问题是当字段定义一样的时候，mysql就可以在这些字段上更快的是用索引（对isam类型的表来说，除非字段定义完全一样，否则不会使用索
引）。在这个前提下，varchar和 char是一样的除非它们定义的长度不一致。由于 tt.actualpc
定义为char(10)，et.employid 定义为 char(15)，二者长度不一致。<br />
为了解决这个问题，需要用 alter table 来加大 actualpc的长度从10到15个字符：<br />
mysql&gt; alter table tt modify actualpc varchar(15);<br />
<br />
现在 tt.actualpc 和 et.employid 都是 varchar(15)<br />
了。再来执行一次 explain 语句看看结果：<br />
table type possible_keys key key_len ref rows extra <br />
tt allassignedpc, null null null 3872 using clientid, where actualpc <br />
do all primary null null null 2135 range checked for each record (keymap: 1) <br />
et_1 all primary null null null 74 range checked for eachrecord (key map: 1) et eq_ref primary primary 15 tt.actualpc 1<br />
<br />
这还不够，它还可以做的更好：现在 rows值乘积已经少了74倍。这次查询需要用2秒钟。<br />
第二个改变是消除在比较 tt.assignedpc = et_1.employid 和 tt.clientid= do.custnmbr 中字段的长度不一致问题：<br />
mysql&gt; alter table tt modify assignedpc varchar(15), -&gt;modify clientid varchar(15);<br />
<br />
现在 explain 的结果如下：<br />
table type possible_keys key key_len ref rows extra <br />
et all primary null null null 74 <br />
tt ref assignedpc, actualpc 15 et.employid 52 using clientid, where actualpc <br />
et_1 eq_ref primary primary 15 tt.assignedpc 1 <br />
do eq_ref primary primary 15 tt.clientid 1<br />
<br />
这看起来已经是能做的最好的结果了。<br />
遗留下来的问题是，mysql默认地认为字段 tt.actualpc的值是均匀分布的，然而表 tt并非如此。幸好，我们可以很方便的让mysql分析索引的分布：<br />
mysql&gt; analyze table tt;<br />
<br />
到此为止，表连接已经优化的很完美了，explain 的结果如下：<br />
table type possible_keys key key_len ref rows extra <br />
tt all assignedpc null null null 3872 using clientid, where actualpc <br />
et eq_ref primary primary 15 tt.actualpc 1 <br />
et_1 eq_ref primary primary 15 tt.assignedpc 1 <br />
do eq_ref primary primary 15 tt.clientid 1<br />
<br />
请注意，explain 结果中的
rows字段的值也是mysql的连接优化程序大致猜测的，请检查这个值跟真实值是否基本一致。如果不是，可以通过在select 语句中使用
straight_join 来取得更好的性能，同时可以试着在from分句中用不同的次序列出各个表。
<img src ="http://www.blogjava.net/persister/aggbug/236813.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/persister/" target="_blank">persister</a> 2008-10-27 10:40 <a href="http://www.blogjava.net/persister/archive/2008/10/27/236813.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>