• [技术干货] MySQL支持中文排序的方法(分享)
    让MySQL支持中文排序编绎MySQL时一般以ISO-8859字符集作为默认的字符集,因此在比较过程中中文编码字符大小写转换造成了这种现象,一种解决方法是对于包含中文的字段加上"binary"属性,使之作为二进制比较,例如将"name char(10)"改成"name char(10)binary"。编译MySQL时使用--with--charset=gbk 参数,这样MySQL就会直接支持中文查找和排序了。mysql order by 中文 排序在MySQL中,我们经常会对一个字段进行排序查询,但进行中文排序和查找的时候,对汉字的排序和查找结果往往都是错误的。 这种情况在MySQL的很多版本中都存在。如果这个问题不解决,那么MySQL将无法实际处理中文。 出现这个问题的原因是因为MySQL在查询字符串时是大小写不敏感的,在编绎MySQL时一般以ISO-8859字符集作为默认的字符集,因此在比较过程中中文编码字符大小写转换造成了这种现象。解决方法:对于包含中文的字段加上"binary"属性,使之作为二进制比较,例如将"name char(10)"改成"name char(10)binary"。如果你使用源码编译MySQL,可以编译MySQL时使用 --with--charset=gbk 参数,这样MySQL就会直接支持中文查找和排序了(默认的是latin1)。也可以用 extra-charsets=gb2312,gbk 来加入多个字符集。如果不想对表结构进行修改或者重新编译MySQL,也可以在查询语句的 order by 部分使用 CONVERT 函数。比如 select * from mytable order by CONVERT(chineseColumnName USING gbk);UTF8 默认校对集是 utf8_general_ci , 它不是按照中文来的。你需要强制让MySQL按中文来排序。select * from core_vender_info order by convert(vender_abbrev USING gbk) COLLATE gbk_chinese_ci
  • [技术干货] MySql分表、分库、分片和分区知识深入详解
    分片是把数据库横向扩展(Scale Out)到多个物理节点上的一种有效的方式,其主要目的是为突破单节点数据库服务器的 I/O 能力限制,解决数据库扩展性问题。Shard这个词的意思是“碎片”。如果将一个数据库当作一块大玻璃,将这块玻璃打碎,那么每一小块都称为数据库的碎片(DatabaseShard)。将整个数据库打碎的过程就叫做分片,可以翻译为分片。形式上,分片可以简单定义为将大数据库分布到多个物理节点上的一个分区方案。每一个分区包含数据库的某一部分,称为一个片,分区方式可以是任意的,并不局限于传统的水平分区和垂直分区。一个分片可以包含多个表的内容甚至可以包含多个数据库实例中的内容。每个分片被放置在一个数据库服务器上。一个数据库服务器可以处理一个或多个分片的数据。系统中需要有服务器进行查询路由转发,负责将查询转发到包含该查询所访问数据的分片或分片集合节点上去执行。Mysql的扩展方案包括Scale Out和Scale Up两种。Scale Out(横向扩展)是指Application可以在水平方向上扩展。一般对数据中心的应用而言,Scale out指的是当添加更多的机器时,应用仍然可以很好的利用这些机器的资源来提升自己的效率从而达到很好的扩展性。Scale Up(纵向扩展)是指Application可以在垂直方向上扩展。一般对单台机器而言,Scale Up值得是当某个计算节点(机器)添加更多的CPU Cores,存储设备,使用更大的内存时,应用可以很充分的利用这些资源来提升自己的效率从而达到很好的扩展性。MySql的Sharding策略包括垂直切分和水平切分两种。垂直(纵向)拆分:是指按功能模块拆分,以解决表与表之间的io竞争。比如分为订单库、商品库、用户库...这种方式多个数据库之间的表结构不同。水平(横向)拆分:将同一个表的数据进行分块保存到不同的数据库中,来解决单表中数据量增长出现的压力。这些数据库中的表结构完全相同。表结构设计垂直切分。常见的一些场景包括a).大字段的垂直切分。单独将大字段建在另外的表中,提高基础表的访问性能,原则上在性能关键的应用中应当避免数据库的大字段b). 按照使用用途垂直切分。例如企业物料属性,可以按照基本属性、销售属性、采购属性、生产制造属性、财务会计属性等用途垂直切分c). 按照访问频率垂直切分。例如电子商务、Web 2.0系统中,如果用户属性设置非常多,可以将基本、使用频繁的属性和不常用的属性垂直切分开表结构设计水平切分。常见的一些场景包括a). 比如在线电子商务网站,订单表数据量过大,按照年度、月度水平切分b). Web 2.0网站注册用户、在线活跃用户过多,按照用户ID范围等方式,将相关用户以及该用户紧密关联的表做水平切分c). 例如论坛的置顶帖子,因为涉及到分页问题,每页都需要显示置顶贴,这种情况可以把置顶贴水平切分开来,避免取置顶帖子时从所有帖子的表中读取分表从表面意思说就是把一张表分成多个小表,分区则是把一张表的数据分成N多个区块,这些区块可以在同一个磁盘上,也可以在不同的磁盘上。分表和分区的区别1,实现方式上mysql的分表是真正的分表,一张表分成很多表后,每一个小表都是完正的一张表,都对应三个文件(MyISAM引擎:一个.MYD数据文件,.MYI索引文件,.frm表结构文件)。2,数据处理上分表后数据都是存放在分表里,总表只是一个外壳,存取数据发生在一个一个的分表里面。分区则不存在分表的概念,分区只不过把存放数据的文件分成了许多小块,分区后的表还是一张表,数据处理还是由自己来完成。3,提高性能上分表后,单表的并发能力提高了,磁盘I/O性能也提高了。分区突破了磁盘I/O瓶颈,想提高磁盘的读写能力,来增加mysql性能。在这一点上,分区和分表的测重点不同,分表重点是存取数据时,如何提高mysql并发能力上;而分区呢,如何突破磁盘的读写能力,从而达到提高mysql性能的目的。4,实现的难易度上分表的方法有很多,用merge来分表,是最简单的一种方式。这种方式和分区难易度差不多,并且对程序代码来说可以做到透明的。如果是用其他分表方式就比分区麻烦了。分区实现是比较简单的,建立分区表,跟建平常的表没什么区别,并且对代码端来说是透明的。分区的适用场景1. 一张表的查询速度已经慢到影响使用的时候。2.表中的数据是分段的3.对数据的操作往往只涉及一部分数据,而不是所有的数据123456789101112131415161718192021CREATE TABLE sales (     id INT AUTO_INCREMENT,     amount DOUBLE NOT NULL,     order_day DATETIME NOT NULL,     PRIMARY KEY(id, order_day) ) ENGINE=Innodb PARTITION BY RANGE(YEAR(order_day)) (     PARTITION p_2010 VALUES LESS THAN (2010),     PARTITION p_2011 VALUES LESS THAN (2011),     PARTITION p_2012 VALUES LESS THAN (2012), PARTITION p_catchall VALUES LESS THAN MAXVALUE);分表的适用场景1. 一张表的查询速度已经慢到影响使用的时候。2.当频繁插入或者联合查询时,速度变慢。分表的实现需要业务结合实现和迁移,较为复杂。
  • [技术干货] mysql Read-Ahead
    If InnoDB can determine there is a high probability that data might be needed soon, it performs read-ahead operations to bring that data into the buffer pool so that it is available in memory. Making a few large read requests for contiguous data can be more efficient than making several small, spread-out requests. There are two read-ahead heuristics in InnoDB:In sequential read-ahead, if InnoDB notices that the access pattern to a segment in the tablespace is sequential, it posts in advance a batch of reads of database pages to the I/O system.In random read-ahead, if InnoDB notices that some area in a tablespace seems to be in the process of being fully read into the buffer pool, it posts the remaining reads to the I/O system.
  • [技术干货] mysql索引的优劣势及规则
    一、索引的优劣势优点:可以快速的检索  、可以加快分组和排序缺点: 占用储存空间、降低数据表的修改操作二、索引的分类    主键索引即主索引,根据主键 pk_clolum(length)建立索引,不允许重复,不允许空值唯一索引用来建立索引的列的值必须是唯一的,允许空值普通索引用表中的普通列构建的索引,没有任何限制全文索引用大文本对象的列构建的索引全文索引用大文本对象的列构建的索引;组合索引用多个列组合构建的索引,这多个列中的值不允许有空值。三、使用索引的规则1、适合建立索引的情况主键自动建立唯一索引;经常作为查询条件在 WHERE 或者 ORDER BY 语句中出现的列要建立索引;作为排序的列要建立索引;查询中与其他表关联的字段,外键关系建立索引;高并发条件下倾向组合索引;用于聚合函数的列可以建立索引,例如使用了 max(column_1)或者count(column_1)时的 column_1 就需要建立索引。2、不适合建立索引的情况经常增删改的列不要建立索引;有大量重复的列不建立索引;表记录太少不要建立索引。3、索引失灵的情况在组合索引中不能有列的值为 NULL,如果有,那么这一列对组合索引就是无效的;LIKE 操作中,'%aaa%'不会使用索引,也就是索引会失效,但是‘aaa%'可以使用索引;在索引的列上使用表达式或者函数会使索引失效;在查询条件中使用不等于,包括<符号、>符号和!=会导致索引失效;在查询条件中使用 IS NULL 或者 IS NOT NULL 会导致索引失效;字符串不加单引号会导致索引失效;在查询条件中使用 OR 连接多个条件会导致索引失效,除非 OR 链接的每个条件都加上索引;如果排序的字段使用了索引,那么 select 的字段也要是索引字段,否则索引失效;尽量不要包括多列排序,如果一定要,最好为这队列构建组合索引。四、关于索引的SQL1、创建表的时候添加索引-- 创建表的时候添加索引-- INDEX 关键词-- myindex 索引的名称自己起的-- (username(16))添加到哪一个字段上CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL, INDEX myindex (username(16)));2、创建表过后添加索引-- 添加索引-- myindex索引的名字(自己定义)-- mytable 表的名字CREATE INDEX myindex ON mytable(username(16));或者ALTER TABLE mytable ADD INDEX myindex(username);3 查看索引-- mytable 表的名字 show index FROM mytable;4、删除索引-- myindex索引的名字(自己定义)-- mytable 表的名字DROP INDEX myindex ON mytable;或者ALTER TABLE mytable DROP INDEX myindex;
  • [技术干货] 细说mysql replace into用法
    replace语句在一般的情况下和insert差不多,但是如果表中存在primary 或者unique索引的时候,如果插入的数据和原来的primary key或者unique相同的时候,会删除原来的数据,然后增加一条新的数据,所以有的时候执行一条replace语句相当于执行了一条delete和insert语句。直接上实例吧:新建一个test表,三个字段,id,title,uid,  id是自增的主键,uid是唯一索引;1234567CREATE TABLE `test` ( `Id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(25) DEFAULT NULL COMMENT '标题', `uid` int(11) DEFAULT NULL COMMENT 'uid', PRIMARY KEY (`Id`), UNIQUE KEY `uid` (`uid`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;insert into test(title,uid) VALUES ('你好','1');insert into test(title,uid) VALUES ('国庆节','2');结果如下:使用 replace into插入数据时:1REPLACE INTO test(title,uid) VALUES ('这次是8天假哦','3');当uid存在时,使用replace into 语句1REPLACE INTO test(title,uid) VALUES ('这是Uid=1的第一条数据哦','1');没有预料到 MySQL 在数据冲突时(也就是uid发生重复数据时)实际上是删掉了旧记录,再写入新记录,。通过以上实例,相信博友们可以看出:replace into 跟 insert 功能类似,不同点在于:replace into 首先尝试插入数据到表中, 1. 如果发现表中已经有此行数据(根据主键或者唯一索引判断)则先删除此行数据,然后插入新的数据。 2. 否则,直接插入新数据。要注意的是:插入数据的表必须有主键或者是唯一索引!否则的话,replace into 会直接插入数据,这将导致表中出现重复的数据。MySQL replace into 有三种形式:1. replace into tbl_name(col_name, ...) values(...)2. replace into tbl_name(col_name, ...) select ...3. replace into tbl_name set col_name=value, ...第一种形式类似于insert into的用法,第二种replace select的用法也类似于insert select,这种用法并不一定要求列名匹配,事实上,MYSQL甚至不关心select返回的列名,它需要的是列的位置。例如,replace into tb1( name, title, mood) select rname, rtitle, rmood from tb2;?这个例子使用replace into从?tb2中将所有数据导入tb1中。第三种replace set用法类似于update set用法,使用一个例如“SET col_name = col_name + 1”的赋值,则对位于右侧的列名称的引用会被作为DEFAULT(col_name)处理。因此,该赋值相当于SET col_name = DEFAULT(col_name) + 1。前两种形式用的多些。其中 “into” 关键字可以省略,不过最好加上 “into”,这样意思更加直观。另外,对于那些没有给予值的列,MySQL 将自动为这些列赋上默认值。
  • [技术干货] s下bat批处理执行Mysql的sql语句
    有时候我们需要用bat来定时执行mysql那么就可以参考下面的代码 直接上代码:123456789101112131415161718192021@ECHO OFF  SET dbhost=主机名(例如:127.0.0.1)SET dbuser=用户名(例如:root)SET dbpasswd=用户密码(例如:root)SET dbName=数据库名称(例如:test)SET sqlpath=%~dp0(此语句可以保证.bat同级目录下的.sql文件能被找到)set sqlfile=update.sql(需要执行执行sql的文件) 进入mysql安装路径的bin目录下,如果配置了环境变量则不需要此语句 (例如:cd /d C:\Program Files\MySQL\MySQL Server 5.5\bin) ::执行SQL脚本 mysql -h%dbhost% -u%dbuser% -p%dbpasswd% < %sqlpath%%sqlfile% --default-character-set=utf8 ECHO 完成!PAUSE @ECHO Done!windows下执行sql文件-批量执行sql语句新建一个txt文件,里面内容如下,改为.cmd文件,点击运行即可:123456789101112rem MySQL_HOME 本地MySQL的安装路径rem host mysql 服务器的ip地址,可以是本地,也可以是远程rem port mysql 服务器的端口,缺省为3306rem user password 具有操作数据库权限的用户名和密码,如rootrem default-character-set 数据库所用的字符集rem database 要连接的数据名,这里用的testrem test.sql 要执行的脚本文件,这里为test.sqlrem mysql 后面的应该放在一行。set MySQL_HOME=C:\mysql-4.1.10-win32set PATH=%MySQL_HOME%\bin;%PATH% mysql --host=192.168.0.66 --port=3306 --user=root --password=123 --default-character-set=utf8 test<test.sqlWindows下批处理执行MySQL脚本文件一、1234567891011121314151617@echo offSetlocal enabledelayedexpansion::CODER BY Mark_Li POWERD BY iBAT 1.6cd "C:\Program Files\MySQL\MySQL Server 5.5\bin":: 数据库名称@set db=hrms:: 用户名@set userName=root:: 密码@set password=:: 要执行的sql脚本@set sqlpath="C:\Program Files\MySQL\MySQL Server 5.5\test_hrms.sql":: 连接MySQL数据库并执行sql脚本 -f 脚本执行过程中,出现错误继续执行 --default-character-set指定导入数据的编码(与数据库编码相同)mysql -f -u %userName% --password=%password% %db% < %sqlpath% --default-character-set=gbk:: 执行完成后,不立刻关闭dos窗口 pause二、设置超时命令在my.ini文件下加入wait_timeout=2880000interactive_timeout = 2880000max_allowed_packet = 100M三、如果要执行多个SQL脚本将test_hrms.sql替换为source "C:\Program Files\MySQL\MySQL Server 5.5\test_hrms.sql" "C:\Program Files\MySQL\MySQL Server 5.5\test_hrms2.sql""C:\Program Files\MySQL\MySQL Server 5.5\test_hrms3.sql"
  • [技术干货] MySQL正确修改最大连接数的三种方式
    我们大家都知道MySQL数据库在安装完之后,默认的MySQL数据库,其最大连接数为100,一般流量稍微大一点的论坛或网站这个连接数是远远不够的,增加默认MySQL连接数的方法有两个。show variables like 'max_connections';方法一:进入MySQL安装目录 打开MySQL配置文件 my.ini 或 my.cnf查找 max_connections=100 修改为 max_connections=1000 服务里重起MySQL即可方法二:MySQL最大连接数默认是100客户端登录:MySQL -uusername -ppassword设置新的MySQL最大连接数为200:MySQL> set GLOBAL max_connections=200显示当前运行的Query:MySQL> show processlist显示当前状态:MySQL> show status退出客户端:MySQL> exit查看当前MySQL最大连接数:MySQLadmin -uusername -ppassword variables方法三:以centos 4.4 下面的MySQL 5.0.33 手工编译版本为例说明:vi /usr/local/MySQL/bin/MySQLd_safe找到safe_MySQLd编辑它,找到MySQLd启动的那两行,在后面加上参数 :-O max_connections=1500
  • [技术干货] MySQL中exists、in及any的基本用法
    【1】exists对外表用loop逐条查询,每次查询都会查看exists的条件语句。当 exists里的条件语句能够返回记录行时(无论记录行是多少,只要能返回),条件就为真 , 返回当前loop到的这条记录。反之如果exists里的条件语句不能返回记录行,条件为假,则当前loop到的这条记录被丢弃。exists的条件就像一个boolean条件,当能返回结果集则为1,不能返回结果集则为 0。语法格式如下:select * from tables_name where [not] exists(select..);示例如下:select * from p_user_2 where EXISTS(select * from p_user where id=12)如果p_user表中有id为12的记录,那么将返回所有p_user_2表中的记录;否则,返回记录为空。如果是not exists,则与上述相反。总的来说,如果A表有n条记录,那么exists查询就是将这n条记录逐条取出,然后判断n遍exists条件【2】in语法格式如下:select * from A where column in (select column from B);需要说明的是,where中,column为A的某一列,in 所对应的子查询语句返回为一列多行结果集。注意,in所对应的select语句返回的结果一定是一列!可以为多行。示例如下:select * from p_user_2 where id [not] in (select id from p_user )查询id在p_user表id集合的p_user_2的记录。not in则相反。【3】exists与in的关系经过sql改变,二者是可以达到同一个目标的:select * from p_user_2 where id [not] in (select id from p_user );select * from p_user_2 where [not] EXISTS (select id from p_user where id = p_user_2.id )那么什么时候用exists 或者in呢?**如果查询的两个表大小相当,那么用in和exists差别不大。 ****如果两个表中一个较小,一个是大表,则子查询表大的用exists,子查询表小的用in: **例如:表A(小表),表B(大表)① 子查询表为表B:select * from A where cc in (select cc from B) //效率低,用到了A表上cc列的索引; select * from A where exists(select cc from B where cc=A.cc) //效率高,用到了B表上cc列的索引。② 子查询表为表A:select * from B where cc in (select cc from A) //效率高,用到了B表上cc列的索引; select * from B where exists(select cc from A where cc=B.cc) //效率低,用到了A表上cc列的索引。ot in 和not exists如果查询语句使用了not in 那么内外表都进行全表扫描,没有用到索引;而not extsts 的子查询依然能用到表上的索引。**所以无论哪个表大,用not exists都比not in要快。 **【4】any/some/all① any,in,some,all分别是子查询关键词之一any 可以与=、>、>=、<、<=、<>结合起来使用,分别表示等于、大于、大于等于、小于、小于等于、不等于其中的任意一个数据。all可以与=、>、>=、<、<=、<>结合是来使用,分别表示等于、大于、大于等于、小于、小于等于、不等于其中的其中的所有数据。它们进行子查询的语法如下:operand comparison_operator any (subquery);operand in (subquery);operand coparison_operator some (subquery);operand comparison_operator all (subquery);any,all关键字必须与一个比较操作符一起使用。② any关键词可以理解为“对于子查询返回的列中的任一数值,如果比较结果为true,则返回true”。例如:select age from t_user where age > any (select age from t_user_copy);假设表t_user 中有一行包含(10),t_user_copy包含(21,14,6),则表达式为true;如果t_user_copy包含(20,10),或者表t_user_copy为空表,则表达式为false。如果表t_user_copy包含(null,null,null),则表达式为unkonwn。all的意思是“对于子查询返回的列中的所有值,如果比较结果为true,则返回true”例如:select age from t_user where age > all (select age from t_user_copy);假设表t_user 中有一行包含(10),t_user_copy包含(21,14,6),则表达式为true;如果t_user_copy包含(20,10),或者表t_user_copy为空表,则表达式为false。如果表t_user_copy包含(null,null,null),则表达式为unkonwn。all的意思是“对于子查询返回的列中的所有值,如果比较结果为true,则返回true”例如:select age from t_user where age > all (select age from t_user_copy);假设表t_user 中有一行包含(10)。如果表t_user_copy包含(-5,0,+5),则表达式为true,因为10比t_user_copy中的查出的所有三个值大。如果表t_user_copy包含(12,6,null,-100),则表达式为false,因为t_user_copy中有一个值12大于10。如果表t_user_copy包含(0,null,1),则表达式为unknown。如果t_user_copy为空表,则结果为true。③ not in /innot in 是 “<>all”的别名,用法相同。语句in 与“=any”是相同的。例如:select s1 from t1 where s1 = any (select s1 from t2);select s1 from t1 where s1 in (select s1 from t2);语句some是any的别名,用法相同。例如:select s1 from t1 where s1 <> any (select s1 from t2);select s1 from t1 where s1 <> some (select s1 from t2);在上述查询中some理解上就容易了“表t1中有部分s1与t2表中的s1不相等”,这种语句用any理解就有错了。
  • [技术干货] MySQL 事务的隔离级别
    查看MySQL隔离级别SELECT @@global.tx_isolation;  SELECT @@session.tx_isolation;  SELECT @@tx_isolation;修改MySQL 隔离级别SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}注意:默认的行为(不带session和global)是为下一个(未开始)事务设置隔离级别。如果你使用GLOBAL关键字,语句在全局对从那点开始创建的所有新连接(除了不存在的连接)设置默认事务级别。你需要SUPER权限来做这个。使用SESSION 关键字为将来在当前连接上执行的事务设置默认事务级别。 任何客户端都能自由改变会话隔离级别(甚至在事务的中间),或者为下一个事务设置隔离级别。
  • [技术干货] MySQL innodb_autoinc_lock_mode 详解
    innodb_auto_lockmode有三个取值:    1、0 这个表示tradition 传统    2、1 这个表示consecutive 连续    3、2 这个表示interleaved 交错
  • [技术干货] SQL中EXPLAIN命令的使用方法
    在日常工作中,我们会有时会开慢查询去记录一些执行时间比较久的SQL语句,找出这些SQL语句并不意味着完事了,些时我们常常用到explain这个命令来查看一个这些SQL语句的执行计划,查看该SQL语句有没有使用上了索引,有没有做全表扫描,这都可以通过explain命令来查看。所以我们深入了解MySQL的基于开销的优化器,还可以获得很多可能被优化器考虑到的访问策略的细节,以及当运行SQL语句时哪种策略预计会被优化器采用。explain显示了mysql如何使用索引来处理select语句以及连接表。可以帮助选择更好的索引和写出更优化的查询语句。使用方法,在select语句前加上explain就可以了:如:explain select surname,first_name form a,b where a.id=b.id 1、EXPLAIN tbl_nameEXPLAIN tbl_name是DESCRIBE tbl_name或SHOW COLUMNS FROM tbl_name的一个同义词。2、EXPLAIN [EXTENDED] SELECT select_options如果在SELECT语句前放上关键词EXPLAIN,MySQL将解释它如何处理SELECT,提供有关表如何联接和联接的次序。借助于EXPLAIN,可以知道什么时候必须为表加入索引以得到一个使用索引来寻找记录的更快的SELECT。还可以知道优化器是否以一个最佳次序联接表。为了强制优化器让一个SELECT语句按照表命名顺序的联接次序,语句应以STRAIGHT_JOIN而不只是SELECT开头。EXPLAIN为用于SELECT语句中的每个表返回一行信息。表以它们在处理查询过程中将被MySQL读入的顺序被列出。MySQL用一遍扫描多次联接(single-sweep multi-join)的方式解决所有联接。这意味着MySQL从第一个表中读一行,然后找到在第二个表中的一个匹配行,然后在第3个表中等等。当所有的表处理完后,它输出选中的列并且返回表清单直到找到一个有更多的匹配行的表。从该表读入下一行并继续处理下一个表。当使用EXTENDED关键字时,EXPLAIN产生附加信息,可以用SHOW WARNINGS浏览。该信息显示优化器限定SELECT语句中的表和列名,重写并且执行优化规则后SELECT语句是什么样子,并且还可能包括优化过程的其它注解。EXPLAIN的每个输出行提供一个表的相关信息,并且每个行包括下面的列:id:SELECT识别符。这是SELECT的查询序列号。select_type:SELECT类型。SIMPLE: 简单SELECT(不使用UNION或子查询)PRIMARY: 最外面的SELECTUNION:UNION中的第二个或后面的SELECT语句DEPENDENT UNION:UNION中的第二个或后面的SELECT语句,取决于外面的查询UNION RESULT:UNION的结果SUBQUERY:子查询中的第一个SELECTDEPENDENT SUBQUERY:子查询中的第一个SELECT,取决于外面的查询DERIVED:导出表的SELECT(FROM子句的子查询)table:表名type:联接类型system:表仅有一行(=系统表)。这是const联接类型的一个特例。const:表最多有一个匹配行,它将在查询开始时被读取。因为仅有一行,在这行的列值可被优化器剩余部分认为是常数。const用于用常数值比较PRIMARY KEY或UNIQUE索引的所有部分时。eq_ref:对于每个来自于前面的表的行组合,从该表中读取一行。这可能是最好的联接类型,除了const类型。它用在一个索引的所有部分被联接使用并且索引是UNIQUE或PRIMARY KEY。eq_ref可以用于使用= 操作符比较的带索引的列。比较值可以为常量或一个使用在该表前面所读取的表的列的表达式。ref:对于每个来自于前面的表的行组合,所有有匹配索引值的行将从这张表中读取。如果联接只使用键的最左边的前缀,或如果键不是UNIQUE或PRIMARY KEY(换句话说,如果联接不能基于关键字选择单个行的话),则使用ref。如果使用的键仅仅匹配少量行,该联接类型是不错的。ref可以用于使用=或<=>操作符的带索引的列。ref_or_null:该联接类型如同ref,但是添加了MySQL可以专门搜索包含NULL值的行。在解决子查询中经常使用该联接类型的优化。index_merge:该联接类型表示使用了索引合并优化方法。在这种情况下,key列包含了使用的索引的清单,key_len包含了使用的索引的最长的关键元素。unique_subquery:该类型替换了下面形式的IN子查询的ref:value IN (SELECT primary_key FROMsingle_table WHERE some_expr);unique_subquery是一个索引查找函数,可以完全替换子查询,效率更高。index_subquery:该联接类型类似于unique_subquery。可以替换IN子查询,但只适合下列形式的子查询中的非唯一索引:value IN (SELECT key_column FROM single_table WHERE some_expr)range:只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引。key_len包含所使用索引的最长关键元素。在该类型中ref列为NULL。当使用=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN操作符,用常量比较关键字列时,可以使用rangeindex:该联接类型与ALL相同,除了只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小。all:对于每个来自于先前的表的行组合,进行完整的表扫描。如果表是第一个没标记const的表,这通常不好,并且通常在它情况下很差。通常可以增加更多的索引而不要使用ALL,使得行能基于前面的表中的常数值或列值被检索出。possible_keys:possible_keys列指出MySQL能使用哪个索引在该表中找到行。注意,该列完全独立于EXPLAIN输出所示的表的次序。这意味着在possible_keys中的某些键实际上不能按生成的表次序使用。key:key列显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。key_len:key_len列显示MySQL决定使用的键长度。如果键是NULL,则长度为NULL。注意通过key_len值我们可以确定MySQL将实际使用一个多部关键字的几个部分。ref:ref列显示使用哪个列或常数与key一起从表中选择行。rows:rows列显示MySQL认为它执行查询时必须检查的行数。Extra:该列包含MySQL解决查询的详细信息。Distinct:MySQL发现第1个匹配行后,停止为当前的行组合搜索更多的行。Not exists:MySQL能够对查询进行LEFT JOIN优化,发现1个匹配LEFT JOIN标准的行后,不再为前面的的行组合在该表内检查更多的行。range checked for each record (index map: #):MySQL没有发现好的可以使用的索引,但发现如果来自前面的表的列值已知,可能部分索引可以使用。对前面的表的每个行组合,MySQL检查是否可以使用range或index_merge访问方法来索取行。Using filesort:MySQL需要额外的一次传递,以找出如何按排序顺序检索行。通过根据联接类型浏览所有行并为所有匹配WHERE子句的行保存排序关键字和行的指针来完成排序。然后关键字被排序,并按排序顺序检索行。Using index:从只使用索引树中的信息而不需要进一步搜索读取实际的行来检索表中的列信息。当查询只使用作为单一索引一部分的列时,可以使用该策略。Using temporary:为了解决查询,MySQL需要创建一个临时表来容纳结果。典型情况如查询包含可以按不同情况列出列的GROUP BY和ORDER BY子句时。Using where:WHERE子句用于限制哪一个行匹配下一个表或发送到客户。除非你专门从表中索取或检查所有行,如果Extra值不为Using where并且表联接类型为ALL或index,查询可能会有一些错误。Using sort_union(...), Using union(...), Using intersect(...):这些函数说明如何为index_merge联接类型合并索引扫描。Using index for group-by:类似于访问表的Using index方式,Using index for group-by表示MySQL发现了一个索引,可以用来查询GROUP BY或DISTINCT查询的所有列,而不要额外搜索硬盘访问实际的表。并且,按最有效的方式使用索引,以便对于每个组,只读取少量索引条目。通过相乘EXPLAIN输出的rows列的所有值,你能得到一个关于一个联接如何的提示。这应该粗略地告诉你MySQL必须检查多少行以执行查询。当你使用max_join_size变量限制查询时,也用这个乘积来确定执行哪个多表SELECT语句。
  • [技术干货] MySQL正确修改最大连接数的3种方案
    我们大家都知道MySQL数据库在安装完之后,默认的MySQL数据库,其最大连接数为100,一般流量稍微大一点的论坛或网站这个连接数是远远不够的,增加默认MySQL连接数的方法有两个。1show variables like 'max_connections';方法一:进入MySQL安装目录 打开MySQL配置文件 my.ini 或 my.cnf查找 max_connections=100 修改为 max_connections=1000 服务里重起MySQL即可方法二:MySQL最大连接数默认是100客户端登录:1MySQL -uusername -ppassword设置新的MySQL最大连接数为200:1MySQL> set GLOBAL max_connections=200显示当前运行的Query:1MySQL> show processlist显示当前状态:1MySQL> show status退出客户端:MySQL> exit查看当前MySQL最大连接数:MySQLadmin -uusername -ppassword variables方法三:以centos 4.4 下面的MySQL 5.0.33 手工编译版本为例说明:1vi /usr/local/MySQL/bin/MySQLd_safe找到safe_MySQLd编辑它,找到MySQLd启动的那两行,在后面加上参数 :1-O max_connections=1500
  • [技术干货] MySQL缓存的查询和清除命令使用分享
    Mysql 查询缓存查询缓存的作用就是当查询接收到一个和之前同样的查询,服务器将会从查询缓存种检索结果,而不是再次分析和执行上次的查询。这样就大大提高了性能,节省时间。1.配置查询缓存修改配置文件,修改[mysqld]下的query_cache_size和query_cache_type(如果没有则添加)。其中query_cache_size表示缓存的大小,而query_cache_type有3个值,表示缓存那种类  型的select结果集,query_cache_type各个值如下:0或off关闭缓存1或on开启缓存,但是不保存使用sql_no_cache的select语句,如不缓存select  sql_no_cache name from wei where id=22或demand开启有条件缓存,只缓存带sql_cache的select语句,缓存select  sql_cache name from wei where id=4例子的配置为下,配置完成重启Mysql服务器即可。query_cache_size=10M query_cache_type=1 可以用如下命令查看是否开启,其中have_query_cache为是否开启,query_cache_limit 指定单个查询能够使用的缓冲区大小,缺省为1M;query_cache_min_res_unit为系统分配的最小缓存块大小,默认是4KB,设置值大对大数据查询有好处,但如果你的查询都是小数据 查询,就容易造成内存碎片和浪费;query_cache_size和query_cache_type就是上面我们的配置;query_cache_wlock_invalidate表示当有其他客户端正在对MyISAM表进行写操作时,如果查询在query cache中,是否返回cache结果还是等写操作完成再读表获取结果。mysql> show variables like '%query_cache%'; +------------------------------+----------+ | Variable_name        | Value  | +------------------------------+----------+ | have_query_cache       | YES   | | query_cache_limit      | 1048576 | | query_cache_min_res_unit   | 4096   | | query_cache_size       | 10485760 | | query_cache_type       | ON    | | query_cache_wlock_invalidate | OFF   | +------------------------------+----------+ 6 rows in set (0.00 sec) 2.测试我们先执行一次,select  count(*) from wei ;然后再执行一次,可以看出第二次用的时间远远低于第一次的执行,因为第二次从缓存中读取了select结果。mysql> select count(*) from wei ; +----------+ | count(*) | +----------+ | 4194304 | +----------+ 1 row in set (3.92 sec) mysql> select count(*) from wei ; +----------+ | count(*) | +----------+ | 4194304 | +----------+ 1 row in set (0.00 sec) 我们可以通过如下命令查看现在缓存的情况mysql> show status like 'qcache%'; +-------------------------+----------+ | Variable_name      | Value  | +-------------------------+----------+ | Qcache_free_blocks   | 1    | | Qcache_free_memory   | 10475424 | | Qcache_hits       | 1    | | Qcache_inserts     | 1    | | Qcache_lowmem_prunes  | 0    | | Qcache_not_cached    | 0    | | Qcache_queries_in_cache | 1    | | Qcache_total_blocks   | 4    | +-------------------------+----------+ 8 rows in set (0.00 sec) 其中各个参数的意义如下:Qcache_free_blocks:缓存中相邻内存块的个数。数目大说明可能有碎片。FLUSH QUERY CACHE会对缓存中的碎片进行整理,从而得到一个空闲块。Qcache_free_memory:缓存中的空闲内存。Qcache_hits:每次查询在缓存中命中时就增大Qcache_inserts:每次插入一个查询时就增大。命中次数除以插入次数就是不中比率。Qcache_lowmem_prunes:缓存出现内存不足并且必须要进行清理以便为更多查询提供空间的次数。这个数字最好长时间来看;如果这个 数字在不断增长,就表示可能碎片非常严重,或者内存很少。(上面的 free_blocks和free_memory可以告诉您属于哪种情况)Qcache_not_cached:不适合进行缓存的查询的数量,通常是由于这些查询不是 SELECT 语句或者用了now()之类的函数。Qcache_queries_in_cache:当前缓存的查询(和响应)的数量。Qcache_total_blocks:缓存中块的数量。清除缓存mysql的FLUSH句法(清除缓存)FLUSH flush_option [,flush_option]如果你想要清除一些MySQL使用内部缓存,你应该使用FLUSH命令。为了执行FLUSH,你必须有reload权限。flush_option可以是下列任何东西:HOSTS       这个用的最多,经常碰见。主要是用来清空主机缓存表。如果你的某些主机改变IP数字,或如果你得到错误消息Host ... isblocked,你应该清空主机表。当在连接MySQL服务器时,对一台给定的主机有多于 max_connect_errors个错误连续不断地发生,MySQL为了安全的需要将会阻止该主机进一步的连接请求。清空主机表允许主机再尝试连接。LOGS        关闭当前的二进制日志文件并创建一个新文件,新的二进制日志文件的名字在当前的二进制文件的编号上加1。PRIVILEGES  这个也是经常使用的,每当重新赋权后,为了以防万一,让新权限立即生效,一般都执行一把,目地是从数据库授权表中重新装载权限到缓存中。TABLES       关闭所有打开的表,同时该操作将会清空查询缓存中的内容。FLUSH TABLES WITH READ LOCK   关闭所有打开的表,同时对于所有数据库中的表都加一个读锁,直到显示地执行unlock tables,该操作常常用于数据备份的时候。STATUS       重置大多数状态变量到0。MASTER        删除所有的二进制日志索引文件中的二进制日志文件,重置二进制日志文件的索引文件为空,创建一个新的二进制日志文件,不过这个已经不推荐使用,改成reset master 了。可以想象,以前自己是多土啊,本来一条简单的命令就可以搞定的,却要好几条命令来,以前的做法是先查出来当前的二进制日志文件名,再用purge 操作。QUERY CACHE   重整查询缓存,消除其中的碎片,提高性能,但是并不影响查询缓存中现有的数据,这点和Flush table 和Reset Query  Cache(将会清空查询缓存的内容)不一样的。SLAVE        类似于重置复制吧,让从数据库忘记主数据库的复制位置,同时也会删除已经下载下来的relay log,与Master一样,已经不推荐使用,改成Reset Slave了。这个也很有用的。  一般来讲,Flush操作都会记录在二进制日志文件中,但是FLUSH LOGS、FLUSH MASTER、FLUSH SLAVE、FLUSH TABLES WITH READ LOCK不会记录,因此上述操作如果记录在二进制日志文件中话,会对从数据库造成影响。
  • [技术干货] mysql如何优化插入记录速度
    插入记录时,影响插入速度的主要是索引、唯一性校验、一次插入记录条数等。根据这些情况,可以分别进行优化,本节将介绍优化插入记录速度的几种方法。一. 对于MyISAM引擎表常见的优化方法如下:1. 禁用索引。对于非空表插入记录时,MySQL会根据表的索引对插入记录建立索引。如果插入大量数据,建立索引会降低插入记录的速度。为了解决这种情况可以在插入记录之前禁用索引,数据插入完毕后在开启索引。禁用索引的语句为: ALTER TABLE tb_name DISABLE KEYS;  重新开启索引的语句为: ALTER TABLE table_name ENABLE KEYS; 对于空表批量导入数据,则不需要进行此操作,因为MyISAM引擎的表是在导入数据之后才建立索引的。    2. 禁用唯一性检查:数据插入时,MySQL会对插入的记录进行唯一性校验。这种唯一性校验也会降低插入记录的速度。为了降低这种情况对查询速度的影响,可以在插入记录之前禁用唯一性检查,等到记录插入完毕之后再开启。禁用唯一性检查的语句为: SET UNIQUE_CHECKS=0; 开启唯一性检查的语句为: SET UNIQUE_CHECKS=1;    3. 使用批量插入。使用一条INSERT语句插入多条记录。如 INSERT INTO table_name VALUES(....),(....),(....)    4. 使用LOAD DATA INFILE批量导入当需要批量导入数据时,使用LOAD DATA INFILE语句导入数据的速度比INSERT语句快。二. 对于InnoDB引擎的表,常见的优化方法如下: 1. 禁用唯一性检查。同MyISAM引擎相同,通过 SET UNIQUE_CHECKS=0;  导入数据之后将该值置1。    2. 禁用外键检查。插入数据之前执行禁止对外键的查询,数据插入完成之后再恢复对外键的检查。禁用外键检查语句为: SET FOREIGN_KEY_CHECKS=0;  恢复对外键的检查语句为: SET FOREIGN_KEY_CHECKS=1; 3. 禁止自动提交。插入数据之前禁止事务的自动提交,数据导入完成之后,执行恢复自动提交操作。禁止自动提交语句为: SET AUTOCOMMIT=0;  恢复自动提交只需将该值置1。
  • [技术干货] Python MySQL Order By
    结果排序请使用 ORDER BY 语句按升序或降序对结果进行排序。ORDER BY 关键字默认按升序对结果进行排序。若要按降序对结果进行排序,请使用 DESC 关键字。实例以字符顺序对姓名进行排序,结果:import mysql.connector mydb = mysql.connector.connect(   host="localhost",   user="yourusername",   passwd="yourpassword",   database="mydatabase" ) mycursor = mydb.cursor() sql = "SELECT * FROM customersORDER BYname" mycursor.execute(sql) myresult = mycursor.fetchall() for x in myresult:   print(x)
总条数:1406 到第 页
上滑加载中