Showing posts with label mysql. Show all posts
Showing posts with label mysql. Show all posts

Wednesday, April 22, 2009

(转)mysql慢查询日志

http://blog.chinaunix.net/u2/61187/showart.php?id=478082


打开mysql的慢查询日志记录


mysql慢查询日志对于跟踪有问题的查询非常有用,可以分析出当前程序里有很耗费资源的sql语句,那如何打开mysql的慢查询日志记录呢?
其实打开mysql的慢查询日志很简单,只需要在mysql的配置文件里(windows系统是my.ini,linux系统是的[mysqld]下面加上如下代码:

log-slow-queries=/var/lib/mysql/slowquery.log
long_query_time=2


:
log-slow-queries 设置把日志写在那里,为空的时候,系统会给慢查询日志赋予主机名,并被附加slow.log. /var/lib/mysql/slowquery.log为日志存放的文件的位置,一般这个目录要有mysql的运行帐号的可写权限,一般都将这个目录设置为mysql的数据存放目录

long_query_time=2中的2表示查询超过两秒才记录.

如果设置了参数log-long-format,那么所有没有使用索引的查询也将被记录。在文件my.cnfmy.ini中加入下面这一行可以记录这些查询

这是一个有用的日志。它对于性能的影响不大(假设所有查询都很快),并且强调了那些最需要注意的查询(丢失了索引或索引没有得到最佳应用)

# Time: 070927 8:08:52

# User@Host: root[root] @ [192.168.0.20]

# Query_time: 372 Lock_time: 136 Rows_sent: 152 Rows_examined: 263630
select id, name from manager where id in (66,10135);
这是慢查询日志中的一条,用了372秒,锁了136秒,返回152行,一共查了263630

如果日志内容很多,用眼睛一条一条去看会累死,mysql自带了分析的工具,使用方法如下:
命令行下,进入mysql/bin目录,输入mysqldumpslow –help--help可以看到这个工具的参数,主要有
Usage: mysqldumpslow [ OPTS... ] [ LOGS... ]

Parse and summarize the MySQL slow query log. Options are

--verbose verbose

--debug debug

--help write this text to standard output

-v verbose

-d debug

-s ORDER what to sort by (t, at, l, al, r, ar etc), 'at' is default

-r reverse the sort order (largest last instead of first)

-t NUM just show the top n queries

-a don't abstract all numbers to N and strings to 'S'

-n NUM abstract numbers with at least n digits within names

-g PATTERN grep: only consider stmts that include this string

-h HOSTNAME hostname of db server for *-slow.log filename (can be wildcard),

default is '*', i.e. match all

-i NAME name of server instance (if using mysql.server startup scrīpt)

-l don't subtract lock time from total time

-s
,是order的顺序,说明写的不够详细,俺用下来,包括看了代码,主要有
c,t,l,r
ac,at,al,ar,分别是按照query次数,时间,lock的时间和返回的记录数来排序,前面加了a的时倒叙
-t
,是top n的意思,即为返回前面多少条的数据
-g
,后边可以写一个正则匹配模式,大小写不敏感的

mysqldumpslow -s c -t 20 host-slow.log
mysqldumpslow -s r -t 20 host-slow.log

上述命令可以看出访问次数最多的20sql语句和返回记录集最多的20sql
mysqldumpslow -t 10 -s t -g “left join” host-slow.log
这个是按照时间返回前10条里面含有左连接的sql语句。

(转)优化MySQL数据库查询的三个方法

在优化查询中,数据库应用(如MySQL)即意味着对工具的操作与使用。使用索引、使用EXPLAIN分析查询以及调整MySQL的内部配置可达到优化查询的目的。 任何一位数据库程序员都会有这样的体会:高通信量的数据库驱动程序中,一条糟糕的SQL查询语句可对整个应用程序的运行产生严重的影响,其不仅消耗掉更多的数据库时间,且它将对其他应用组件产生影响。 如同其它学科,优化查询性能很大程度上决定于开发者的直觉。幸运的是,像MySQL这样的数据库自带有一些协助工具。本文简要讨论诸多工具之三种:使用索引,使用EXPLAIN分析查询以及调整MySQL的内部配置。

1: 使用索引 
MySQL允许对数据库表进行索引,以此能迅速查找记录,而无需一开始就扫描整个表,由此显著地加快查询速度。每个表最多可以做到16个索引,此外 MySQL还支持多列索引及全文检索。  给表添加一个索引非常简单,只需调用一个CREATE INDEX命令并为索引指定它的域即可。
列表A给出了一个例子:
mysql> CREATE INDEX idx_username ON users(username);
Query OK, 1 row affected (0.15 sec)
Records: 1 Duplicates: 0 Warnings: 0

 这里,对users表的username域做索引,以确保在WHERE或者HAVING子句中引用这一域的SELECT查询语句运行速度比没有添加索引时要快。通过SHOW INDEX命令可以查看索引已被创建(列表B):
mysql> SHOW INDEX FROM users;
--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| users | 1 | idx_username | 1 | username | A | NULL | NULL | NULL | YES | BTREE | |65g站长资讯
--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
1 row in set (0.00 sec)

 值得注意的是:索引就像一把双刃剑。对表的每一域做索引通常没有必要,且很可能导致运行速度减慢,因为向表中插入或修改数据时,MySQL不得不每次都为这些额外的工作重新建立索引。另一方面,避免对表的每一域做索引同样不是一个非常好的主意,因为在提高插入记录的速度时,导致查询操作的速度减慢。这就需要找到一个平衡点,比如在设计索引系统时,考虑表的主要功能(数据修复及编辑)不失为一种明智的选择。

2: 使用Explain分析优化查询性能 
在分析查询性能时,考虑EXPLAIN关键字同样很管用。EXPLAIN关键字一般放在SELECT查询语句的前面,用于描述MySQL如何执行查询操作、以及MySQL成功返回结果集需要执行的行数。下面的一个简单例子可以说明(列表C)这一过程:
mysql> EXPLAIN SELECT city.name, city.district FROM city, country WHERE city.countrycode = country.code AND country.code = 'IND';
+----+-------------+---------+-------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+---------------+---------+---------+-------+------+-------------+
| 1 | SIMPLE | country | const | PRIMARY | PRIMARY | 3 | const | 1 | Using index |
| 1 | SIMPLE | city | ALL | NULL | NULL | NULL | NULL | 4079 | Using where |
+----+-------------+---------+-------+---------------+---------+---------+-------+------+-------------+
2 rows in set (0.00 sec)

这里查询是基于两个表连接。EXPLAIN关键字描述了MySQL是如何处理连接这两个表。必须清楚的是,当前设计要求MySQL处理的是 country表中的一条记录以及city表中的整个4019条记录。这就意味着,还可使用其他的优化技巧改进其查询方法。例如,给city表添加如下索引(列表D):
mysql> CREATE INDEX idx_ccode ON city(countrycode);
Query OK, 4079 rows affected (0.15 sec)
Records: 4079 Duplicates: 0 Warnings: 0

现在,当我们重新使用EXPLAIN关键字进行查询时,我们可以看到一个显著的改进(列表E): 列表 E mysql> EXPLAIN SELECT city.name, city.district FROM city, country WHERE city.countrycode = country.code AND country.code = 'IND';
+----+-------------+---------+-------+---------------+-----------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+---------------+-----------+---------+-------+------+-------------+
| 1 | SIMPLE | country | const | PRIMARY | PRIMARY | 3 | const | 1 | Using index |
| 1 | SIMPLE | city | ref | idx_ccode | idx_ccode | 3 | const | 333 | Using where |
+----+-------------+---------+-------+---------------+-----------+---------+-------+------+-------------+
2 rows in set (0.01 sec)  在这个例子中,MySQL现在只需要扫描city表中的333条记录就可产生一个结果集,其扫描记录数几乎减少了90%!自然,数据库资源的查询速度更快,效率更高。

3: 调整内部变量 
MySQL是如此的开放,所以可轻松地进一步调整其缺省设置以获得更优的性能及稳定性。需要优化的一些关键变量如下:改变索引缓冲区长度(key_buffer)

 一般,该变量控制缓冲区的长度在处理索引表(读/写操作)时使用。MySQL使用手册指出该变量可以不断增加以确保索引表的最佳性能,并推荐使用与系统内存25%的大小作为该变量的值。这是MySQL十分重要的配置变量之一,如果你对优化和提高系统性能有兴趣,可以从改变key_buffer_size变量的值开始。 改变表长(read_buffer_size)

 当一个查询不断地扫描某一个表,MySQL会为它分配一段内存缓冲区。read_buffer_size变量控制这一缓冲区的大小。如果你认为连续扫描进行得太慢,可以通过增加该变量值以及内存缓冲区大小提高其性能。 设定打开表的数目的最大值(table_cache)

 该变量控制MySQL在任何时候打开表的最大数目,由此能控制服务器响应输入请求的能力。它跟max_connections变量密切相关,增加table_cache值可使MySQL打开更多的表,就如增加max_connections值可增加连接数一样。当收到大量不同数据库及表的请求时,可以考虑改变这一值的大小。对缓长查询设定一个时间限制(long_query_time)

 MySQL带有“慢查询日志”,它会自动地记录所有的在一个特定的时间范围内尚未结束的查询。这个日志对于跟踪那些低效率或者行为不端的查询以及寻找优化对象都非常有用。

long_query_time变量控制这一最大时间限定,以秒为单位。  以上讨论并给出用于分析和优化SQL查询的三种工具的使用方法,以此提高你的应用程序性能。使用它们快乐地优化吧!

(转)MySQL索引分析和优化

作者:松下客 来源:赛迪网

一、什么是索引?

索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存。如果没有索引,执行查询时 MySQL必须从第一个记录开始扫描整个表的所有记录,直至找到符合要求的记录。表里面的记录数量越多,这个操作的代价就越高。如果作为搜索条件的列上已 经创建了索引,MySQL无需扫描任何记录即可迅速得到目标记录所在的位置。如果表有1000个记录,通过索引查找记录至少要比顺序扫描记录快100倍。

假设我们创建了一个名为people的表:

CREATE TABLE people ( peopleid SMALLINT NOT NULL, name CHAR(50) NOT NULL )

然后,我们完全随机把1000个不同name值插入到people表。下图显示了people表所在数据文件的一小部分:

可以看到,在数据文件中name列没有任何明确的次序。如果我们创建了name列的索引,MySQL将在索引中排序name列:

对于索引中的每一项,MySQL在内部为它保存一个数据文件中实际记录所在位置的"指针"。因此,如果我们要查找 name等于"Mike"记录的peopleid(SQL命令为"SELECT peopleid FROM people WHERE name=\'Mike\';"),MySQL能够在name的索引中查找"Mike"值,然后直接转到数据文件中相应的行,准确地返回该行的 peopleid(999)。在这个过程中,MySQL只需处理一个行就可以返回结果。如果没有"name"列的索引,MySQL要扫描数据文件中的所有 记录,即1000个记录!显然,需要MySQL处理的记录数量越少,则它完成任务的速度就越快。

二、索引的类型

  MySQL提供多种索引类型供选择:

  • 普通索引
    这是最基本的索引类型,而且它没有唯一性之类的限制。普通索引可以通过以下几种方式创建:
    • 创建索引,例如CREATE INDEX <索引的名字> ON tablename (列的列表);
    • 修改表,例如ALTER TABLE tablename ADD INDEX [索引的名字] (列的列表);
    • 创建表的时候指定索引,例如CREATE TABLE tablename ( [...], INDEX [索引的名字] (列的列表) );
  • 唯一性索引
    这种索引和前面的"普通索引"基本相同,但有一个区别:索引列的所有值都只能出现一次,即必须唯一。唯一性索引可以用以下几种方式创建:
    • 创建索引,例如CREATE UNIQUE INDEX <索引的名字> ON tablename (列的列表);
    • 修改表,例如ALTER TABLE tablename ADD UNIQUE [索引的名字] (列的列表);
    • 创建表的时候指定索引,例如CREATE TABLE tablename ( [...], UNIQUE [索引的名字] (列的列表) );
  • 主键
    主键是一种唯一性索引,但它必须指定为"PRIMARY KEY"。如果你曾经用过AUTO_INCREMENT类型的列,你可能已经熟悉主键之类的概念了。主键一般在创建表的时候指定,例如"CREATE TABLE tablename ( [...], PRIMARY KEY (列的列表) ); "。但是,我们也可以通过修改表的方式加入主键,例如"ALTER TABLE tablename ADD PRIMARY KEY (列的列表); "。每个表只能有一个主键。
  • 全文索引
    MySQL从3.23.23版开始支持全文索引和全文检索。在MySQL中,全文索引的索引类型为FULLTEXT。 全文索引可以在VARCHAR或者TEXT类型的列上创建。它可以通过CREATE TABLE命令创建,也可以通过ALTER TABLE或CREATE INDEX命令创建。对于大规模的数据集,通过ALTER TABLE(或者CREATE INDEX)命令创建全文索引要比把记录插入带有全文索引的空表更快。本文下面的讨论不再涉及全文索引,要了解更多信息,请参见MySQL documentation

三、单列索引与多列索引

索引可以是单列索引,也可以是多列索引。下面我们通过具体的例子来说明这两种索引的区别。假设有这样一个people表:

CREATE TABLE people ( peopleid SMALLINT NOT NULL AUTO_INCREMENT, firstname CHAR(50) NOT NULL, lastname CHAR(50) NOT NULL, age SMALLINT NOT NULL, townid SMALLINT NOT NULL, PRIMARY KEY (peopleid) );

下面是我们插入到这个people表的数据:

这个数据片段中有四个名字为"Mikes"的人(其中两个姓Sullivans,两个姓McConnells),有两个年龄为17岁的人,还有一个名字与众不同的Joe Smith。

这个表的主要用途是根据指定的用户姓、名以及年龄返回相应的peopleid。例如,我们可能需要查找姓名为 Mike Sullivan、年龄17岁用户的peopleid(SQL命令为SELECT peopleid FROM people WHERE firstname=\'Mike\' AND lastname=\'Sullivan\' AND age=17;)。由于我们不想让MySQL每次执行查询就去扫描整个表,这里需要考虑运用索引。

首先,我们可以考虑在单个列上创建索引,比如firstname、lastname或者age列。如果我们创建 firstname列的索引(ALTER TABLE people ADD INDEX firstname (firstname);),MySQL将通过这个索引迅速把搜索范围限制到那些firstname=\'Mike\'的记录,然后再在这个"中间结果集 "上进行其他条件的搜索:它首先排除那些lastname不等于"Sullivan"的记录,然后排除那些age不等于17的记录。当记录满足所有搜索条 件之后,MySQL就返回最终的搜索结果。

由于建立了firstname列的索引,与执行表的完全扫描相比,MySQL的效率提高了很多,但我们要求 MySQL扫描的记录数量仍旧远远超过了实际所需要的。虽然我们可以删除firstname列上的索引,再创建lastname或者age列的索引,但总 地看来,不论在哪个列上创建索引搜索效率仍旧相似。

为了提高搜索效率,我们需要考虑运用多列索引。如果为firstname、lastname和age这三个列创建一个多列索引,MySQL只需一次检索就能够找出正确的结果!下面是创建这个多列索引的SQL命令:

ALTER TABLE people ADD INDEX fname_lname_age (firstname,lastname,age);

由于索引文件以B-树格式保存,MySQL能够立即转到合适的firstname,然后再转到合适的lastname,最后转到合适的age。在没有扫描数据文件任何一个记录的情况下,MySQL就正确地找出了搜索的目标记录!

那么,如果在firstname、lastname、age这三个列上分别创建单列索引,效果是否和创建一个 firstname、lastname、age的多列索引一样呢?答案是否定的,两者完全不同。当我们执行查询的时候,MySQL只能使用一个索引。如果 你有三个单列的索引,MySQL会试图选择一个限制最严格的索引。但是,即使是限制最严格的单列索引,它的限制能力也肯定远远低于firstname、 lastname、age这三个列上的多列索引。

四、最左前缀

多列索引还有另外一个优点,它通过称为最左前缀(Leftmost Prefixing)的概念体现出来。继续考虑前面的例子,现在我们有一个firstname、lastname、age列上的多列索引,我们称这个索引 为fname_lname_age。当搜索条件是以下各种列的组合时,MySQL将使用fname_lname_age索引:

  • firstname,lastname,age
  • firstname,lastname
  • firstname

从另一方面理解,它相当于我们创建了(firstname,lastname,age)、(firstname,lastname)以及(firstname)这些列组合上的索引。下面这些查询都能够使用这个fname_lname_age索引:

SELECT peopleid FROM people WHERE firstname=\'Mike\' AND lastname=\'Sullivan\' AND age=\'17\';

SELECT peopleid FROM people WHERE firstname=\'Mike\' AND lastname=\'Sullivan\';

SELECT peopleid FROM people WHERE firstname=\'Mike\'; The following queries cannot use the index at all:

SELECT peopleid FROM people WHERE lastname=\'Sullivan\';

SELECT peopleid FROM people WHERE age=\'17\'; SELECT peopleid FROM people WHERE lastname=\'Sullivan\' AND age=\'17\';

五、选择索引列

在性能优化过程中,选择在哪些列上创建索引是最重要的步骤之一。可以考虑使用索引的主要有两种类型的列:在WHERE子句中出现的列,在join子句中出现的列。请看下面这个查询:

SELECT age ## 不使用索引 FROM people WHERE firstname=\'Mike\' ## 考虑使用索引 AND lastname=\'Sullivan\' ## 考虑使用索引

这个查询与前面的查询略有不同,但仍属于简单查询。由于age是在SELECT部分被引用,MySQL不会用它来限制列选择操作。因此,对于这个查询来说,创建age列的索引没有什么必要。下面是一个更复杂的例子:

SELECT people.age, ##不使用索引 town.name ##不使用索引 FROM people LEFT JOIN town ON people.townid=town.townid ##考虑使用索引 WHERE firstname=\'Mike\' ##考虑使用索引 AND lastname=\'Sullivan\' ##考虑使用索引

与前面的例子一样,由于firstname和lastname出现在WHERE子句中,因此这两个列仍旧有创建索引的必要。除此之外,由于town表的townid列出现在join子句中,因此我们需要考虑创建该列的索引。

那么,我们是否可以简单地认为应该索引WHERE子句和join子句中出现的每一个列呢?差不多如此,但并不完 全。我们还必须考虑到对列进行比较的操作符类型。MySQL只有对以下操作符才使用索引:<,<=,=,>,& gt;=,BETWEEN,IN,以及某些时候的LIKE。可以在LIKE操作中使用索引的情形是指另一个操作数不是以通配符(%或者_)开头的情形。例 如,"SELECT peopleid FROM people WHERE firstname LIKE \'Mich%\';"这个查询将使用索引,但"SELECT peopleid FROM people WHERE firstname LIKE \'%ike\';"这个查询不会使用索引。

六、分析索引效率

现在我们已经知道了一些如何选择索引列的知识,但还无法判断哪一个最有效。MySQL提供了一个内建的SQL命令帮助我们完成这个任务,这就是EXPLAIN命令。EXPLAIN命令的一般语法是:EXPLAIN <SQL命令>。你可以在MySQL文档找到有关该命令的更多说明。下面是一个例子:

EXPLAIN SELECT peopleid FROM people WHERE firstname=\'Mike\' AND lastname=\'Sullivan\' AND age=\'17\';

这个命令将返回下面这种分析结果:

table type possible_keys key key_len ref rows Extra
people ref fname_lname_age fname_lname_age 102 const,const,const 1 Where used

下面我们就来看看这个EXPLAIN分析结果的含义。

  • table:这是表的名字。
  • type:连接操作的类型。下面是MySQL文档关于ref连接类型的说明:

    "对于每一种与另一个表中 记录的组合,MySQL将从当前的表读取所有带有匹配索引值的记录。如果连接操作只使用键的最左前缀,或者如果键不是UNIQUE或PRIMARY KEY类型(换句话说,如果连接操作不能根据键值选择出唯一行),则MySQL使用ref连接类型。如果连接操作所用的键只匹配少量的记录,则ref是一 种好的连接类型。"

    在本例中,由于索引不是UNIQUE类型,ref是我们能够得到的最好连接类型。

    如果EXPLAIN显示连接类型是"ALL",而且你并不想从表里面选择出大多数记录,那么MySQL的操作效率将非常低,因为它要扫描整个表。你可以加入更多的索引来解决这个问题。预知更多信息,请参见MySQL的手册说明。
  • possible_keys
    可能可以利用的索引的名字。这里的索引名字是创建索引时指定的索引昵称;如果索引没有昵称,则默认显示的是索引中第一个列的名字(在本例中,它是"firstname")。默认索引名字的含义往往不是很明显。
  • Key
    它显示了MySQL实际使用的索引的名字。如果它为空(或NULL),则MySQL不使用索引。
  • key_len
    索引中被使用部分的长度,以字节计。在本例中,key_len是102,其中firstname占50字节,lastname占50字节,age占2字节。如果MySQL只使用索引中的firstname部分,则key_len将是50。
  • ref
    它显示的是列的名字(或单词"const"),MySQL将根据这些列来选择行。在本例中,MySQL根据三个常量选择行。
  • rows
    MySQL所认为的它在找到正确的结果之前必须扫描的记录数。显然,这里最理想的数字就是1。
  • Extra
    这里可能出现许多不同的选项,其中大多数将对查询产生负面影响。在本例中,MySQL只是提醒我们它将用WHERE子句限制搜索结果集。

七、索引的缺点

到目前为止,我们讨论的都是索引的优点。事实上,索引也是有缺点的。

首先,索引要占用磁盘空间。通常情况下,这个问题不是很突出。但是,如果你创建每一种可能列组合的索引,索引文件体积的增长速度将远远超过数据文件。如果你有一个很大的表,索引文件的大小可能达到操作系统允许的最大文件限制。

第二,对于需要写入数据的操作,比如DELETE、UPDATE以及INSERT操作,索引会降低它们的速度。这是因为MySQL不仅要把改动数据写入数据文件,而且它还要把这些改动写入索引文件。

【结束语】在大型数据库中,索引是提高速度的一个关键因素。不管表的结构是多么简单,一次500000行的表扫描 操作无论如何不会快。如果你的网站上也有这种大规模的表,那么你确实应该花些时间去分析可以采用哪些索引,并考虑是否可以改写查询以优化应用。要了解更多 信息,请参见MySQL manual。另外注意,本文假定你所使用的MySQL是3.23版,部分查询不能在3.22版MySQL上执行。

Thursday, March 12, 2009

mysql乱码问题之水落石出

问题:本地数据库直接复制了原服务器上的数据文件,包含一个host表,但在本地mysql中,select显示结果总是乱码,而用php调用确可正常显示.而在本地新建的表(utf8),确能在utf8编码环境下的mysql终端显示,却无法在php中正常显示,通过在php中的mysql_connect()后,加入mysql_query("set names utf8")后,可正常显示,但host表又不可显示.

show create database 和show create table显示都是使用utf8编码.
原来服务器上的配置文件:
[mysqld]
character_set_server=ascii
我的机子上的配置文件:
[mysqld]
default-character-set = utf8

原来服务器上:
mysql> show variables like "character%";
+--------------------------+----------------------------------------+
| Variable_name | Value |
+--------------------------+----------------------------------------+
| character_set_client | latin1 |
| character_set_connection | latin1 |
| character_set_database | gbk |
| character_set_filesystem | binary |
| character_set_results | latin1 |
| character_set_server | gbk |
| character_set_system | utf8 |
| character_sets_dir | /usr/local/mysql/share/mysql/charsets/ |
+--------------------------+----------------------------------------+

我的机子上:
mysql> show variables like "character%";
+--------------------------+----------------------------------------+
| Variable_name | Value |
+--------------------------+----------------------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /usr/local/mysql/share/mysql/charsets/ |
+--------------------------+----------------------------------------+
8 rows in set (0.01 sec)

几个关键的变量含义如下:
(1)character_set_server:The server character set and collation are
used as default values if the database character set and collation
are not specified in CREATE DATABASE statements. They have no other purpose.
(2)character_set_database:The database character set and collation
are used as default values if the table character set and
collation are not specified in CREATE
TABLE statements. The database character set also is used by LOAD DATA INFILE. The character set and collation have no other purposes.
• What character set is the statement in when it leaves the client?
The server takes the character_set_client system variable to be the character set in which statements are sent by the client.
• What character set should the server translate a statement to after receiving it?
For this, the server uses the character_set_connection and collation_connection system variables. It converts
statements sent by the client from character_set_client to character_set_connection (except for string literals
that have an introducer such as _latin1 or _utf8). collation_connection is important for comparisons of literal strings.
For comparisons of strings with column values, collation_connection does not matter because columns have their own col-
lation, which has a higher collation precedence.

• What character set should the server translate to before shipping result sets or error messages back to the client?
The character_set_results system variable indicates the character set in which the server returns query results to the client.
This includes result data such as column values, and result metadata such as column names.
mysql根据以上变量,自动执行的编码转换(注意:此处转换只是按新的编码方式将原文字编码成新字符,并非修改编码):
(1)mysql接收查询语句时,如果有必要的话,自动执行将查询语句从character_set_client转换成character_set_connection编码.
(2)如果是insert语句,如果有必要的话,则还要根据表中定义的编码类型,完成一次转换,存入数据库中.
(3)返回结果时,如果有必要的话,完成表中编码类型向character_set_results编码类型的转换.
此处,"有必要"是指两端的两种编码方式不同.在使用php来和mysql通信的话,character_set_client只是起指示作用,并不一定保证php传过来的查询语句就是该编码.其正确性应由用户来保证.

问题应该是这样的:::
在原来的服务器上:
php发送查询语句(utf8格式)给mysql,
(1)由于character_set_client和character_set_connection都使用的是latin1编码,所以不用转换;
(2)如果是insert语句,由于表中数据为utf8编码,character_set_connection为latin1编码,数据(utf8)经历一次从latin1到utf8的转换,再存入!
(3)返回结果时,由于表中数据为utf8编码,character_set_results为latin1编码,数据(latin1_to_utf8(utf8))再经历一次从utf8->latin1的转换.最终结果还是utf8!
注意:(1)单纯的utf8->latin时,由于utf8"兼容"所有的字符集,故utf8中有些字符可能latin1中没有,这种转换可能导致信息丢失.但latin1->utf8不会.本例(1)中,utf8数据被错误的当成latin1被转换时,也可能出现某些字段无法对应latin1字符集,可能出错,所以虽然以上的方式一般显示的结果是正确的,但我觉得还是有必要将其改正过来.
(2)"For comparisons of strings with column values, collation_connection does not matter because columns have their own col-
lation, which has a higher collation precedence."--说明以上的转换不会影响对列值的匹配.因为列值的匹配有它自己的匹配规则,无论开始被转换成什么乱码,最终都会被转换成和列值同样的编码,再进行匹配(再次强调,编码转换只是改变解析方式,并不改变编码;同样的编码,不同的解析方式,被认为是不匹配的).

在我的机子上:
我机子上的表是复制服务器上的表,所以表里面的数据仍然是latin_to_utf8(utf8)格式的.但我的character set都设成了utf8.所以整个查询过程中,都不会进行编码转换,最终输出的就是latin_to_utf8(utf8)--乱码!无论你将终端界面的字符编码怎么设置,终会是乱码,只不过可能是不同形式的乱码而已.
另外,还有一个值得注意的地方,必须设置相应的collation_database和collation_server,否则在select查询时匹配每个列中的中文时,会显示空集.
原有服务器:
+----------------------+-------------------+
| Variable_name | Value |
+----------------------+-------------------+
| collation_connection | latin1_swedish_ci |
| collation_database | gbk_chinese_ci |
| collation_server | gbk_chinese_ci |
+----------------------+-------------------+
通过set @@global. collation_database=utf8_general_ci
set @@global. collation_server=utf8_general_ci,
重新登陆mysql可见,不加@@global.只对当前session有效.
最终在我的机子上:
mysql> show variables like "collation%";
+----------------------+-----------------+
| Variable_name | Value |
+----------------------+-----------------+
| collation_connection | utf8_general_ci |
| collation_database | utf8_general_ci |
| collation_server | utf8_general_ci |
+----------------------+-----------------+

好了,原理都弄清了,解决办法也就浮出水面了:
(1)保持原有mysql变量,set names latin1;
(2)mysqldump -uroot -p --default-character-set=latin1 hcdata host > /mysql/a.sql;
(3)更正环境变量:set names utf8;
(4)备份原有host表alter table host rename host_backup
(5)导入a.sql:进入mysql后,执行命令source /mysql/a.sql
或直接 mysql -uroot -p hcdata </mysql/a.sql

下面这篇文章都以上几个参数做了几个试验,很不错.
http://chenzs19850728.blog.163.com/blog/static/7629609200868104214954/

Friday, March 06, 2009

mysql删除root用户后的解决办法

一不小心,把root用户给删除了.结果,登陆时,输入密码总不对,提示:
MYSQL ERROR 1045 (28000): Access denied for user (using password: YES)
不输入密码,反倒可以进去,但少了很多权限,有些数据库看不到.开始还以为谁把我的数据库给删了呢.

解决办法:
1.关闭mysql服务--直接kill.
2.mysqld_safe --user=mysql --skip-grant-tables --skip-networking
3.重新启动mysql服务,并mysql -uroot mysql登陆.
4.添加root用户:INSERT INTO user(host, user, password, select_priv, insert_priv, update_priv,...) VALUES ('localhost', 'root', PASSWORD(‘yourpassword’), 'Y', 'Y','Y'...);

再次重启mysql服务后,就ok了.

(转)mysql常用命令

转自:http://hi.baidu.com/%D4%C6%CB%AF%C1%CB/blog/item/d47057366fd0d1daa2cc2b65.html

1. 连接mysql:
mysqlbinmysql -h主机地址 -u 用户名 -p 用户密码

2.退出mysql:exit

3. 修改密码:
mysqlbinmysqladmin -uroot -p(oldpassword) password newpassword

4.增加用户:
添加一个用户test1 密码为ABC;让他可以在任何主机上登录,并对所有数据库有查询、插入、修改、删除的权限。首先用以root用户连入

mysql,然后键入以下命令:grant select,insert,update,delete on *.* to test1@"%" Identified
by "abc";

增加一个用户test2密码为abc,让其只可以在localhost上登录,并可以对数据库mydb进行查询、插入、修改、删除的操作(localhost指本地

主机,即mysql数据库所在的那台主机),这样用户即使用知道test2的密码,也无法从internet上直接访问数据库,只能通过mysql主机上的web页

来访问了。grant select,insert,update,delete on mydb.* to test2@localhost identified by "abc";

增加一个可以从任何地方连接服务器的一个完全的超级用户
grant all privileges on *.* to
test3@"%" identified by 'password' with grant option;

5.删除授权
revoke select,insert,update,delete om *.* from
test2@localhost ;

--------------------------------------------------------

6.显示数据库
show databases;

7.显示数据库中的表
use dataname;
show tables;

8.显示表的结构
describe tablesname;

9.建库
create database 库名;

10.建表
use dataname;
create table teacher //建立表TEACHER
(
id int(3) auto_increment not null primary key,
name char(10) not null,
address varchar(50) default '深圳',
year date
); //建表结束
//以下为插入字段
insert into teacher values('','glchengang','深圳一中','1976-10-10');
insert into teacher values('','jack','深圳一中','1975-12-23');

注:在建表中
(1) 将ID设为长度为3的数字字段:int(3),并让它每个记录自动加一: auto_increment,
并不能为空:not null,而且让它成为主字段primary key
(2) 将NAME设为长度为10的字符字段
(3) 将ADDRESS设为长度50的字符字段,而且缺省值为深圳。varchar和char有什么区别
呢,只有等以后的文章再说了。
(4) 将YEAR设为日期字段。
如果你在mysql提示符键入上面的命令也可以,但不方便调试。 你可以将以上命令
原样写入一个文本文件中假设为school.sql,然后复制到c:下,并在DOS状态进入目录
mysql in,然后键入以下命令:
mysql -uroot -p密码 < c:school.sql
如果成功,空出一行无任何显示;如有错误,会有提示。(以上命令已经调试,你
只要将//的注释去掉即可使用)。


11.删除库和删除表
drop dataname;
drop tablename;

12.将表中的记录清空
delete from tablename;

13.显示表中的记录
select * from tablename;

14.表重命名
alter table t1 rename t2


---------------------------------------------------------

15. 备份数据库
mysqlbinmysqldump -h(ip) -uroot -p(password) databasename > database.sql

16. 恢复数据库
mysqlbinmysql -h(ip) -uroot -p(password) databasename <>

17.复制数据库
mysqldump --all-databases > all-databases.sal

18.备份表
mysqlbinmysqldump -h(ip) -uroot -p(password) databasename tablename > tablename.sql

19.恢复表(操作前先把原来的表删除)
mysqlbinmysql -h(ip) -uroot -p(password) databasename tablename <>

----------------------------------------------------------

20.为了改变列a,从INTEGER改为TINYINT NOT NULL(名字一样),
并且改变列b,从CHAR(10)改为CHAR(20),同时重命名它,从b改为c:
ALTER TABLE t2 MODIFY a TINYINT NOT NULL, CHANGE b c CHAR(20);

增加一个新TIMESTAMP列,名为d:
ALTER TABLE t2 ADD d TIMESTAMP;

在列d上增加一个索引,并且使列a为主键:
ALTER TABLE t2 ADD INDEX (d), ADD PRIMARY KEY (a);

删除列c:
ALTER TABLE t2 DROP COLUMN c;

增加一个新的AUTO_INCREMENT整数列,命名为c:
ALTER TABLE t2 ADD c INT UNSIGNED NOT NULL AUTO_INCREMENT,ADD INDEX (c);
注意,我们索引了c,因为AUTO_INCREMENT柱必须被索引,并且另外我们声明c为NOT NULL,
因为索引了的列不能是NULL

---------------------------------------------------------------

21.数据的导入导出
A。mysqlimport
语法:mysqlbinmysqlimport database tables.txt( 文件名需要与表名相同)
参数:-d or --delete 新数据导入数据表中之前删除数据数据表中的所有信息;
-f or --force 不管是否遇到错误,mysqlimport将强制继续插入数据;
-i or --ignore mysqlimport跳过或者忽略那些有相同唯一关键字的行, 导入文件中的数据将被忽略;
-l or -lock-tables 数据被插入之前锁住表,这样就防止了, 你在更新数据库时,用户的查询和更新受到影响;
--fields-enclosed- by= char
  指定文本文件中数据的记录时以什么括起的, 很多情况下数据以双引号括起。 默认的情况下数据是没有被字符括起的。
  --fields-terminated- by=char
  指定各个数据的值之间的分隔符,在句号分隔的文件中,分隔符是句号。您可以用此选项指定数据之间的分隔符。默认的分隔符是跳格符

(Tab)
  --lines-terminated- by=str
  此选项指定文本文件中行与行之间数据的分隔字符串 或者字符。 默认的情况下mysqlimport以newline为行分隔符。 您可以选择用一个字

符串来替代一个单个的字符: 一个新行或者一个回车。
  mysqlimport命令常用的选项还有-v 显示版本(version), -p 提示输入密码(password)等。

--------------------------------------------------------------

22.常用插入、修改、删除语句
插入记录:insert into teacher values('','glchengang','深圳一中','1976-10-10');
修改记录:update mytable set single=′y′ where name=′abccs′;
删除记录:delete from mytable where name=′abc′;

Insist On

English words
Go to bed at 23:30

About Me

Gtalk:l0he1g at gmail
Location:Beijing,China