新一代MySQL高可用:MySQL Plus

在基于MySQL传统复制的时代(MySQL版本低于5.5)MHA在MySQL高可用中可以说是独领风骚。在MySQL 5.6及GTID的出现后,MHA在这方面就显的不给力,和MHA作者交流,作者基本放弃该软件的维护,MHA作者现就职在Facebook,也没在使用MHA,他也认为在GTID环境下MHA存在的价值不大,不过你如果你还在使用传统复制,还是可以考虑使用MHA做主从的高可用(太老了,建议升级)。

下面我们围绕以下几点来讨论一下:

  1. 在MySQL 5.7 后为什么不需要MHA
  2. MySQL Plus 是什么,能解决什么问题
  3. MySQL Plus看他们如何搞定金融支持

MySQL 5.7后为什么不需要MHA

基于MySQL 5.7 GTID复制已经成熟,另外基于MySQL5.7的增强半同步性进一步提升: 所以在使用MySQL 5.7的复制可以使用: MySQL 5.7+GTID+增强半步, 在该结构中, 不存在会丢数据的问题。 所以MHA在这个结构基本失去了存在的意义。

但使用: MySQL 5.7+GTID+增强半步,也意为着新的知识,可能需要DBA同学们也要更新一下知识。而且在MySQL 5.7中引入binlog group commit, 又是对复制的一个加速。 所以说MySQL5.7 在复制完整性及性能上都有较大的提升,建议没升级的同学尽快升级了。

官方对MySQL 5.7的测试传送门: https://www.mysql.com/why-mysql/benchmarks/

MySQL Plus是什么,能解决什么问题

在3306π北京活动中 青云的蒙哲分享了青云RDS中高可用组件: MySQL Plus。 MySQL Plus是基于一套Raft构建的MySQL中自动选主及维护主从的套件,整体结构如下:

在该结构中Xenon之间会进行通信,在该结构中推荐三个节点的MySQL构建复制,听作者讲也支持两个节点的MySQL构建集群。

在MySQL Plus主要解决:

  1.  集群切换的强一致性(从上面架构看,更多的依赖于MySQL增强半同步,MySQL Plus在控制切换时,会做复制完成校验,从而且保证数据一致)
  2. 主从秒级别切换
  3. 无中心化自动选主

MySQL Plus看他们如何搞定金融环境

MySQL Plus 可以简单的理解是一个MySQL 5.7 GTID增强半同步复制的高可用管理组件。 在MySQL半同步配置方面,为了支持金融业务,青云给的配置如下:

  • rpl_semi_sync_master_wait_no_slave=ON
  • rpl_semi_sync_master_timeout=1000000000000000000
  • rpl_semi_sync_master_wait_point=AFTER_SYNC

看到这个配置我才想明白为什么他们建议是三个节点,在rpl_semi_sync_master_timeout配置上可以说不允许退化到异步复制, 另外RadonDB负责人交流,在MySQL Plus架构中主节点上至少要求一个Slave给半同步应答。 所以2个节点对架构的稳定性也是一个保证。 另外在金融环境中,作者推荐所有请求都在主库上完成, 免的存在复制延迟造成交易数据异常。

在金融架构中,青云也提供一套基于MySQL Plus之上构建建的分库分表机制, 基于MySQL的事务强一致性约,在该平台支持OLTP和OLAP更感觉有点NewSQL的感觉。

下面是官方给的一个总结:

重大消息

如果想了解更多3306π是青云MySQL Plus PPT信息可以关注 3306pai公众号,回复“bj”获取 3306π北京的PPT打包下载。

MySQL Plus 官方要开源了,希望通过MySQL Plus给MySQL 5.7 GTID复制提供一个新的高可用方案。

更重大消息: QingCloud RDS : RadonDB也要开源了,大家期待一下吧。 如果感兴趣提前体验或是更多的关注 RadonDB发展,也可以加到QQ群:748415432  和群主及 RadonDB负责人直接对喊话。   技术在于相互沟通,你的建议也需是将来一个非常不错的功能。

作者:吴炳锡 来源:http://wubx.net/ 联系方式: wubingxi#163.com 转载请注明作/译者和出处,并且不能用于商业用途,违者必究.

招商银行为什么使用MySQL

      对于金融行业使用MySQL可以说也比较早,例如腾讯的财富通从开始到现都是基于MySQL构建,但对于传统银行企业使用MySQL我也是一直存在好奇的想法。 这次在3306π北京站有幸听了招商银行王龙的分享也解决了我几个疑问,特Mark一下。

  1. 招商银行在走向开源的道路为什么选择了MySQL,而不是其它数据库?
  2. 招商银行在使用MySQL大概的规模及情况是什么?
  3. 招商银行是如何管理他们的MySQL?
  4. 他们成功的心得是什么?

招商银行为什么选择了MySQL?

在这一点上,听作者讲他们内部也做了大量的调研,例如PostgreSQL,TiDB,MySQL等。 最终选择了MySQL,不是说MySQL最优秀,也不是其它DB不优秀, 更重要的MySQL可以对他们的业务模型的支撑上更方便一点,同时团队的更加容易上手。具体的原因如下:
  1. 明确业务模型,不为可能需要的功能买单. MySQL足以支持现有的业务, 而且基准测试性能不弱。
  2. 本着简单的原则,不选复杂。 更多的人熟悉,更利于团队开发。
  3. 组建分布式DB,更方便快速扩容。
  4. 通过主从复制,读写分离等技术,更方便的实现多地多活技术。
  5. 选择MySQL更利用云服务化和DevOPS开发。

招商银行在MySQL使用上大概的规模

目前招商银行在使用MySQL将近两年, 目前作者讲有单业务集群分片在上百规模。 按这个分片来推算可以说是我听过最大的MySQL分布式系统。 该集群主要用于银行帐单查询相关业务。

招商银行如何管理他们的MySQL

这个直接引入原文中的PPT吧。 真的不能小看招商银行两年时间在MySQL云化平台做的相当出色。
上面可以看出来他们在资源申请上分三个类型,对于资源对齐方面确实做的不错。 想做MySQL平台的同学,仔细看看上面的两个图片。

招商银行在MySQL大规模使用上成功的心得

在这点招商银行总结金融架构13条(请阅读PPT),也很赞。 这里限于篇幅不在逻列。 我更多的关注对方在MySQL上的使用,这里看一个他们的分库分表决策: 分库常见几个基本问题: 在分库分表中作者见解也比较独到。也可以说是经过实际项目磨练出来的经验。 PPT已经发布在3306π的公众号上,关注3306pai公众号,回复“bj” 获取全部PPT。 作者:吴炳锡 来源:http://wubx.net/ 联系方式: wubingxi#163.com 转载请注明作/译者和出处,并且不能用于商业用途,违者必究.

MySQL每秒57万的写入,带你飞

一、需求

一个朋友接到一个需求,从大数据平台收到一个数据写入在20亿+,需要快速地加载到MySQL中,供第二天业务展示使用。

二、实现再分析

对于单表20亿, 在MySQL运维,说真的这块目前涉及得比较少,也基本没什么经验,但对于InnoDB单表Insert 如果内存大于数据情况下,可以维持在10万-15万行写入。 但很多时间我们接受的项目还是数据超过内存的。 这里使用XeLabs TokuDB做一个测试。

三、XeLabs TokuDB介绍

项目地址: https://github.com/XeLabs/tokudb

相对官方TokuDB的优化:

  • 内置了jemalloc 内存分配
  • 引入更多的内置的TokuDB性能指标
  • 支持Xtrabackup备份
  • 引入ZSTD压缩算法
  • 支持TokuDB的binlog_group_commit特性

四、测试表

TokuDB核心配置:

loose_tokudb_cache_size=4G
loose_tokudb_directio=ON
loose_tokudb_fsync_log_period=1000
tokudb_commit_sync=0

表结构

CREATE TABLE `user_summary` (
  `user_id` bigint(20) unsigned NOT NULL COMMENT '用户id/手机号',
  `weight` varchar(5) DEFAULT NULL COMMENT '和码体重(KG)',
  `level` varchar(20) DEFAULT NULL COMMENT '重量级',
  `beat_rate` varchar(12) DEFAULT NULL COMMENT '击败率',
  `level_num` int(10) DEFAULT NULL COMMENT '同吨位人数',
  UNIQUE KEY `u_user_id` (`user_id`)
) ENGINE=TokuDB DEFAULT CHARSET=utf8

利用load data写入数据

root@localhost [zst]>LOAD DATA INFILE '/u01/work/134-136.txt' \
INTO TABLE user_summary(user_id, weight, level, beat_rate,level_num);
Query OK, 200000000 rows affected (5 min 48.30 sec)
Records: 200000000  Deleted: 0  Skipped: 0  Warnings: 0

计算一下每秒写入速度:

root@localhost [zst]>select 200000000/(5*60+48.30);
+------------------------+
| 200000000/(5*60+48.30) |
+------------------------+
|            574217.6285 |
+------------------------+
1 row in set (0.00 sec)

文件大小:

-rw-r--r-- 1 root  root  8.5G 11月 25 20:05 134-136.txt
-rw-r----- 1 mysql mysql 8.6K 11月 25 20:44 user_summary.frm
-rw-r----- 1 mysql mysql 3.5G 11月 25 20:51 user_summary_main_229_1_1d_B_0.tokudb

实际文件8.5G,写入TokuDB大小3.5G,只是接近于一半多点的压缩量。 对于20亿数据写入,实际测试在58分钟多点就可以完成。可以满足实际需求,另外对于磁盘IO比较好的机器(SSD类盘,云上的云盘),如果内存和数据差不多情况,这量级数据量测试在Innodb里需要添加自增列,可以在3个小多一点完成。 从最佳实战上来看,Innodb和TokuDB都写入同样的数据,InnoDB需要花大概是TokuDB3-4倍时间。文件大小区别,同样20亿数据:

-rw-r----- 1 mysql mysql  35G 11月 25 23:29 user2_main_26a_1_1d_B_0.tokudb
-rw-r----- 1 mysql mysql 176G 11月 26 03:32 user5.ibd

文件大小在5倍大小的区别。

测试结论:

利用TokuDB在某云环境中8核8G内存,500G高速云盘环境,多次测试可以轻松实现57万每秒的写入量。

另外测试几种场景也供大家参考: 如果在TokuDB中使用带自增的主键,主键无值让MySQL内部产生写入速度,下降比较明显,同样写入2亿数据,带有自建主键:

root@localhost [zst]>CREATE TABLE `user3` (
    ->    `user_id` bigint(20) unsigned NOT NULL COMMENT '用户id/手机号',
    ->    `weight` varchar(5) DEFAULT NULL COMMENT '和码体重(KG)',
    ->    `level` varchar(20) DEFAULT NULL COMMENT '重量级',
    ->    `beat_rate` varchar(12) DEFAULT NULL COMMENT '击败率',
    ->    `level_num` int(10) DEFAULT NULL COMMENT '同吨位人数',
    ->    `id` bigint(20) NOT NULL AUTO_INCREMENT,
    ->    PRIMARY KEY (`id`),
    ->    UNIQUE KEY `u_user_id` (`user_id`)
    ->  ) ENGINE=TokuDB;
Query OK, 0 rows affected (0.03 sec)

root@localhost [zst]>LOAD DATA INFILE '/u01/work/134-136.txt' INTO TABLE user3(user_id, weight, level, beat_rate,level_num);
Query OK, 200000000 rows affected (22 min 43.62 sec)
Records: 200000000  Deleted: 0  Skipped: 0  Warnings: 0

同样的数据写入在主键自增无值产生时,不能使用TokuDB的 Bulk loader data特性,相当于转换为了单条的Insert实现,所以效果上慢太多。

关于TokuDB Bulk Loader前提要求,这个表是空表,对于自增列,如自增列有值的情况下,也可以使用。 建议实际使用中,如果自增列有值的情况下,可以考虑去除自增属性,改成唯一索引,这样减少自增的一些处理逻辑,让TokuDB能跑地更快一点。  另外在Bulk Loader处理中为了追求更快速的写入,压缩方面并不是很好。

关于TokuDB Bulk Loader :https://github.com/percona/PerconaFT/wiki/TokuFT-Bulk-Loader

五、测试环境说明

测试使用CentOS7环境,编译的XeLabs TokuDB版本百度云地址:https://pan.baidu.com/s/1qYRyH3I 。

如果这个地址失效,可以加入QQ群:579036588 联系群主获取。

也可以参考 https://github.com/XeLabs/tokudb/wiki/How-to-build  自行编译。

祝各位玩的开心。

 

作者:吴炳锡 来源:http://wubx.net/ 联系方式: wubingxi#163.com 转载请注明作/译者和出处,并且不能用于商业用途,违者必究.

讨论数据库减库存几种方法V1

MySQL在电子商务网站使用越来越多,做为第一梯队做MySQL的从业人员,也经常被问到MySQL对于减库存在这块有什么好的处理方法?对于这个问题,想想在课上分享及朋友中交流讲的不下百次。 所以也有了把这个总结一下的想法。
对于减库存的操作,我们需要先从一个更高的Level来看一下,先不用讨论update减1的问题。我们可以把减库存形为简单的分成以下几种:

  • 团购类减库存(库存无限,卖的越多越好) 这个可能大家见的也比较多,就不用多说,这类业务,多卖一些老板反而高兴。
  • 限时活动类(24小时活动产品)
  • 秒杀抢购类活动
  • 正常商品售卖

当然还别的形式,可能有的减订单操作是一个复合型的业务: 如 12306这样的业务,含秒杀,抢购,限时活动于一身,难度空前绝后:)

那么我们再来看一下订单系统里几个难题:
1. 超卖,听说某米是允许在商品接近预警时自动关闭交易(商品下架),并允许一定的超售现象。
2. 羊毛党下单不支付,活动结束,一个也没卖出去。 有的电商的做法是,付款后再减库存,不付款不减,可能出现的问题是,用户犹豫一下,去付款时,告诉你没货了,体验不好。
3. 高并发的抢购,打压到DB中,把DB打死的问题。比较常见的一个问题,早些年某电商还发布过把MySQL死锁去掉的分支,用于支撑抢购里业务,现在MySQL 8.0天生支持,另外也可以考虑在在业务层Nginx上控制。

那么我再回过来看一下减库存的形式,我们可以把减库存,分为两种:

  • 正常商品售卖类减库存
  • 活动促销类减库存

问题分为:是否允许超卖 ,要不要考虑羊毛党的一些形为。 处理好这些问题的情况下支撑高并发业务。另外给老板们提个醒,系统优化是一个全面工作,不只是这里有瓶颈。

我分成几种情况来讨论:

  1. 用户下单减库存 如果允许超卖的情况下, 外加一个预警商品下架(缺货)逻辑来处理,基本可以很快速的跑起来。 业务逻辑最简单适合正常商品逻辑。库存大于多少可以上架之类的一些处理(后台人工调配) 如果不允许超卖, 例如车票这类,处理的办法不在是简单的库存结构设计,可以把每个坐位做为一个商品上架构, 只是车票商品上的属性有自已是那个车,挨着谁之类的信息即可。下单后锁定30分钟… 可以目前各大电商的主流逻辑,只是不同的平台,锁时时间不一样。 防止用户下单后几天后还不支付,让商品可以回归库存,不支付订单的失效过程。 下单减库存也是大家最容易接受的一个形为,但这里把最难的问题抛给了平台,一个商品多少没支付返回库存,目前来看不同平台处理的形为不一样。 不适用于抢购,秒杀点业务。
  2. 支付减库存
    抢购,秒杀,谁先付款谁得的逻辑。 这样可以避免羊毛党下单后不支付的形为,例如,本来只有10个特价产品,羊毛党手快,下单成功,但种种原因没支付,提示商品已售完,但活动结束了,一个商品也没卖出去,老板花的活动费白花了。
  3. 高并发的抢购业务
    例如某米周二中午的抢购,10万个商品,可能是100万人在抢购,这种形为,如果都打到DB,可能是对DB的锁也是一个挑战,可能出现的形为就是不该慢的也慢了,去除检查也是一个好办法。
    现在聪明的人类想好了更好的办法,利用Nginx+LUA引入接入在接层引入摇号方法,基于Cookie在Nginx层拿到了可以购买的资格再往后面放,如果没拿到这个资格就在Nginx上看看,提示你商品已经售完就行。这样每次扩容,只用扩一下Nginx接入层就Ok了,其它不用扩了。

问题分类后,现在来看,对于减库存,如果分类处理后,你会发现,还是挺容易处理的,这里面里也不要再来找我聊用MySQL的乐观锁控制来减库存了,如果你在知数堂的课上学习过,一定会知道多点写入的乐观锁控制会造成更新丢失的现象,同样来讲,单节点的同时并发,不是串行的情况,这事没戏,我确时见过有的公司在这块用了串行事务,他们也跑的挺好,业务量不大。祝你玩的开心。也祝愿你们早日在减库存这块遇到瓶颈,让老板高兴痛苦的给你加薪。

 

作者:吴炳锡 来源:http://wubx.net/ 联系方式: wubingxi#163.com 转载请注明作/译者和出处,并且不能用于商业用途,违者必究.

优化MySQL的21个建议

作者:吴炳锡 来源:http://www.mysqlsupport.cn/ 联系方式: wubingxi#gmail.com 转载请注明作/译者和出处,并且不能用于商业用途,违者必究.

今天一个朋友向我咨询怎么去优化 MySQL,我按着思维整理了一下,大概粗的可以分为21个方向。 还有一些细节东西(table cache, 表设计,索引设计,程序端缓存之类的)先不列了,对一个系统,初期能把下面做完也是一个不错的系统。

1. 要确保有足够的内存

数据库能够高效的运行,最关建的因素需要内存足更大了,能缓存住数据,更新也可以在内存先完成。但不同的业务对内存需要强度不一样,一推荐内存要占到数据的15-25%的比例,特别的热的数据,内存基本要达到数据库的80%大小。

2. 需要更多更快的CPU

MySQL 5.6可以利用到64个核,而MySQL每个query只能运行在一个CPU上,所以要求更多的CPU,更快的CPU会更有利于并发。

3. 要选择合适的操作系统

在官方建议估计最推荐的是Solaris, 从实际生产中看CentOS, REHL都是不错的选择,推荐使用CentOS, REHL 版本为6以后的,当然Oracle Linux也是一个不错的选择。虽然从MySQL 5.5后对Windows做了优化,但也不推荐在高并发环境中使用windows.

4. 合理的优化系统的参数

更改文件句柄  ulimit –n 默认1024 太小

进程数限制  ulimit –u   不同版本不一样

禁掉NUMA  numctl –interleave=all

5. 选择合适的内存分配算法

默认的内存分配就是c的malloc 现在也出现许多优化的内存分配算法:

jemalloc and tcmalloc

从MySQL 5.5后支持声明内存储方法。

[mysqld_safe]

malloc-lib = tcmalloc

 

或是直接指到so文件

[mysqld_safe]

malloc-lib=/usr/local/lib/libtcmalloc_minimal.so

 

6. 使用更快的存储设备ssd或是固态卡

存储介质十分影响MySQL的随机读取,写入更新速度。新一代存储设备固态ssd及固态卡的出现也让MySQL 大放异彩,也是淘宝在去IOE中干出了一个漂亮仗。

7. 选择良好的文件系统

推荐XFS, Ext4,如果还在使用ext2,ext3的同学请尽快升级别。 推荐XFS,这个也是今后一段时间Linux会支持一个文件系统。

文件系统强烈推荐: XFS

 

8. 优化挂载文件系统的参数

挂载XFS参数:

(rw, noatime,nodiratime,nobarrier)

挂载ext4参数:

ext4 (rw,noatime,nodiratime,nobarrier,data=ordered)

如果使用SSD或是固态盘需要考虑:

• innodb_page_size = 4K

• Innodb_flush_neighbors = 0

 

9. 选择适合的IO调度

正常请下请使用deadline 默认是noop

echo dealine >/sys/block/{DEV-NAME}/queue/scheduler

 

10. 选择合适的Raid卡Cache策略

请使用带电的Raid,启用WriteBack, 对于加速redo log ,binary log, data file都有好处。

 

11. 禁用Query Cache

Query Cache在Innodb中有点鸡肋,Innodb的数据本身可以在Innodb buffer pool中缓存,Query Cache属于结果集缓存,如果开启Query Cache更新写入都要去检查query cache反而增加了写入的开销。

在MySQL 5.6中Query cache是被禁掉了。

 

12. 使用Thread Pool

现在一个数据对应5个以上App场景比较,但MySQL有个特性随着连接增多的情况下性能反而下降,所以对于连接超过200的以后场景请考虑使用thread pool. 这是一个伟大的发明。

13. 合理调整内存

13.1 减少连接的内存分配

连接可以用thread_cache_size缓存,观查属于比较属不如thread pool给力。数据库在连上分配的内存如下: max_used_connections * (

read_buffer_size +

read_rnd_buffer_size +

join_buffer_size +

sort_buffer_size +

binlog_cache_size +

thread_stack +

2 * net_buffer_length …

)

13.2 使较大的buffer pool

要把60-80%的内存分给innodb_buffer_pool_size.  这个不要超过数据大小了,另外也不要分配超过80%不然会利用到swap.

 

 

14. 合理选择LOG刷新机制

Redo Logs:

– innodb_flush_log_at_trx_commit  = 1 // 最安全

– innodb_flush_log_at_trx_commit  = 2 //  较好性能

– innodb_flush_log_at_trx_commit  = 0 //  最好的情能

binlog :

binlog_sync = 1  需要group commit支持,如果没这个功能可以考虑binlog_sync=0来获得较佳性能。

数据文件:

innodb_flush_method = O_DIRECT

 

15. 请使用Innodb表

可以利用更多资源,在线alter操作有所提高。 目前也支持非中文的full text, 同时支持Memcache API访问。目前也是MySQL最优秀的一个引擎。

如果你还在MyISAM请考虑快速转换。

 

16. 设置较大的Redo log

以前Percona 5.5和官方MySQL 5.5比拼性能时,胜出的一个Tips就是分配了超过4G的Redo log ,而官方MySQL5.5 redo log不能超过4G. 从 MySQL 5.6后可以超过4G了,通常建Redo log加起来要超过500M。 可以通过观查redo log产生量,分配Redo log大于一小时的量即可。

17. 优化磁盘的IO

innodb_io_capactiy 在sas 15000转的下配置800就可以了,在ssd下面配置2000以上。

在MySQL 5.6:

innodb_lru_scan_depth =  innodb_io_capacity / innodb_buffer_pool_instances

innodb_io_capacity_max  =  min(2000, 2 * innodb_io_capacity)

 

18. 使用独立表空间

目前来看新的特性都是独立表空间支持:

truncate table 表空间回收

表空间传输

较好的去优化碎片等管理性能的增加,

整体上来看使用独立表空间是没用的。

19. 配置合理的并发

innodb_thread_concurrency =并发这个参数在Innodb中变化也是最频繁的一个参数。不同的版本,有可能不同的小版本也有变动。一般推荐:

在使用thread pool 的情况下:

innodb_thread_concurrency = 0 就可以了。

如果在没有thread pool的情况下:

5.5 推荐:innodb_thread_concurrency =16 – 32

5.6 推荐innodb_thread_concurrency = 36

20. 优化事务隔离级别

默认是 Repeatable read

推荐使用Read committed  binlog格式使用mixed或是Row

较低的隔离级别 = 较好的性能

21. 注重监控

任环境离不开监控,如果少了监控,有可能就会陷入盲人摸象。 推荐zabbix+mpm构建监控。

MySQL版本和SSIS不兼容问题分析及解决办法

作者:吴炳锡 来源:http://www.mysqlsupport.cn/ 联系方式: wubingxi#gmail.com 转载请注:译者和出处,并且不能用于商业用途,违者必究.
线上替换Percona版本和SSIS不兼容问题分析及解决办法

现象:
利用SSIS(SQL Server Intelligence Services)访问Percona-Server 5.1 原来的SQL取不到数据。
如果加上limit后就能取到数据。但原来的MySQL版本(MySQL-5.1.43sp1)就可以取到数据。
MySQL版本:Percona-Server-5.1.55 or MySQL-5.1.55后
SSIS 从MySQL中取不到数据。

分析:
从WireShark抓包分SSIS执行SQL的流程:
1. PING 包
2. INIT_DB连接上数据库
3. 发送:set sql_select_limit=0;
4. 执行SSIS中定义的SQL;
5. 发送: set sql_select_limit=-1;
6. 再执行SSIS中定义的SQL;

问题发生在哪呢?

第一次set sql_select_limit=0 是因为在早期的数据库交互中,因为mysql没有SQL编译的及SQL正确否的校验,
所以很多程序员会用set sql_select_limit=0这个然后再执行SQL看有返回的错误不。
从协义上看第一次set sql_select_limit=0在Percona-Server-5.1.55及后面的SQL执行都是正确执行的。
然后第二次调用:set sql_select_limit=-1; 目的是把环境变量sql_select_limit还原成default值。
然后再执行SSIS中的SQL.读取读取不到信息。

猜测:

  在执行set sql_select_limit=-1没能执行成功造成后面SSIS再次执行SQL没返回。

有了以上的信息去验证一下:

mysql> select @@version_comment, @@version;
+--------------------------------------------------------------+--------------------+
| @@version_comment | @@version |
+--------------------------------------------------------------+--------------------+
| Percona Server with XtraDB (GPL), Release 12.6, Revision 200 | 5.1.55-rel12.6-log |
+--------------------------------------------------------------+--------------------+
1 row in set (0.00 sec)
mysql>  select user from mysql.user where user="root";
+------+
| user |
+------+
| root |
| root |
+------+
2 rows in set (0.00 sec)
mysql>  set sql_select_limit=0;
Query OK, 0 rows affected (0.00 sec)
mysql>  select user from mysql.user where user="root";
Empty set (0.00 sec)
mysql> set sql_select_limit=-1;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql>  select user from mysql.user where user="root";
Empty set (0.00 sec)
mysql> set sql_select_limit=default;
Query OK, 0 rows affected (0.00 sec)
mysql> select user from mysql.user where user="root";
+------+
| user |
+------+
| root |
| root |
+------+
2 rows in set (0.00 sec)
mysql>  set sql_select_limit=-1;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> show warnings;
+---------+------+--------------------------------------------------+
| Level | Code | Message |
+---------+------+--------------------------------------------------+
| Warning | 1292 | Truncated incorrect sql_select_limit value: '-1' |
+---------+------+--------------------------------------------------+
1 row in set (0.00 sec)

可见在执行:set sql_select_limit=-1; 这个负1是不支持的。从手册上来看,也只是说了一个可以给的最大值,也没说最少值。该参数还是挺鬼疑的。
有兴趣的可以试一下mysql-5.1.54及以下版本或是MySQL-5.1.55以后的版本。
我试了MySQL-5.1.56一样对:set sql_select_limit=-1是不支持。
现在在来看为什么加上limit都可以显示数据呢?
手册里描述:If a SELECT has a LIMIT clause, the LIMIT takes precedence over the value of sql_select_limit.
可见SELECT中的limit运算优先于sql_select_limit。

验证:

mysql>  select user from mysql.user where user="root" limit 10;
+------+
| user |
+------+
| root |
| root |
+------+
2 rows in set (0.00 sec)
mysql>  set sql_select_limit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> select user from mysql.user where user="root";
Empty set (0.00 sec)

如何解决这个问题:
原因是set sql_select_limit=-1没正确执行。
可以在SSIS中的SQL前添加set sql_selct_limit=default;该解决方法存在性能问题,但能正确执行了。
最彻底的解决办法:反溃给那MS支持方,SQL调用中的set sql_select_limit=-1改成 set sql_select_limit=default。

影响:
如果该问题不修正,目前这个SSIS只能使用MySQL-5.1.54前的版本了。
参考:
http://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_sql_select_limit

感想:
不是开源的东西,你知道为什么,知道怎么改,也无语啊。

案例:一个引号带来的查询性能提升

作者:吴炳锡 来源:http://www.mysqlsupport.cn/ 联系方式: wubingxi#gmail.com 转载请注:译者和出处,并且不能用于商业用途,违者必究.
今天看了一个优化案例觉的挺有代表性,这里记录下来做一个标记,来纪念一下随便的字段定义的问题。

回忆一下,在表的设计中很多人习惯的把表的结构设计成Varchar(64),Varchar(255)之类的,虽然大多数情况只存了5-15个字节.那么我看一下下面这个案例.
查询语句:

	SELECT SQL_NO_CACHE channel, COUNT(channel) AS visitors FROM xxx_sources WHERE client_id = 1301 GROUP BY client_id, channel;

该表(client_id,channel)是一个组合索引.
利用explain,看一下执行计划,对于索引使用上看上非常完美

mysql> explain SELECT SQL_NO_CACHE channel, COUNT(channel) AS visitors FROM xxx_sources WHERE client_id = 1301 GROUP BY client_id, channel;
+----+-------------+-------------+-------+--------------------+--------------------+---------+------+----------+--------------------------+
| id | select_type | table       | type  | possible_keys      | key                | key_len | ref  | rows     | Extra                    |
+----+-------------+-------------+-------+--------------------+--------------------+---------+------+----------+--------------------------+
|  1 | SIMPLE      | xxx_sources | index | idx_client_channel | idx_client_channel | 1032    | NULL | 20207319 | Using where; Using index |
+----+-------------+-------------+-------+--------------------+--------------------+---------+------+----------+--------------------------+
1 row in set (0.00 sec)

看一下实际执行:

mysql> SELECT SQL_NO_CACHE channel, COUNT(channel) AS visitors FROM xxx_sources WHERE client_id = 1301 GROUP BY client_id, channel;
+---------+----------+
| channel | visitors |
+---------+----------+
| NULL    |        0 |
+---------+----------+
1 row in set (11.69 sec)

实际执行的情况非常的糟糕.传通的想法,这个执行从索引上执行计划上看非常完美了,好象和MySQL没什么关系了. 在去看一下表的设计会发现client_id也是设计成了
varchar(255).看到这里不防可以使用下面的方法试一下:

mysql> explain SELECT SQL_NO_CACHE channel, COUNT(channel) AS visitors FROM xxx_sources WHERE client_id = '1301' GROUP BY client_id, channel;
+----+-------------+-------------+------+--------------------+--------------------+---------+-------+--------+--------------------------+
| id | select_type | table       | type | possible_keys      | key                | key_len | ref   | rows   | Extra                    |
+----+-------------+-------------+------+--------------------+--------------------+---------+-------+--------+--------------------------+
|  1 | SIMPLE      | xxx_sources | ref  | idx_client_channel | idx_client_channel | 258     | const | 457184 | Using where; Using index |
+----+-------------+-------------+------+--------------------+--------------------+---------+-------+--------+--------------------------+
1 row in set (0.00 sec)

从执行计划上来看,差不多,但实际差多了.具体上来看key_len从1032降到了258,执行计划变成了const基于等于的查找,行数从原来千万级到了十万级了.不算也能明白IO
节省了很多.
再来看实际执行:

mysql> SELECT SQL_NO_CACHE channel, COUNT(channel) AS visitors FROM xxx_sources WHERE client_id = '1301' GROUP BY client_id, channel;
+---------+----------+
| channel | visitors |
+---------+----------+
| NULL    |        0 |
+---------+----------+
1 row in set (0.25 sec)

哇,从11.69秒变成了0.25秒,这是什么概念,优化了多少倍,算一下吧.

看到这里在想什么呢,记住这个案例,嗯,不错,以后还可以加引号优化一下.那为什么不问一下,能不能在优化了,为什么会这样呢?
我们先来看一下第一个问题:
能不能在优化了?
答案是当然可以了.从索引的长度上来看258还是一个非常大的数据,对于client_id这个字段从名字上来看,也只会存数据型的值,那为什么不用的一个int unsigned去存呢,
索引的长度马上会从258降到4。这样不是又节省了很多吗?
接下来看一下第二个问题,为什么会这样呢?
原因有两点,同时基于一个原则,基于成本的优化器。对于client_id在表的定义时定义成了字符型的值,在查询时传入了数值型的值,需要经过一个数值转换,悲剧的开始,最终
导致MySQL选择了一个完成的索引去扫描。

从这个案例上,我们需要注意什么呢?
合理的选择数据类型,基本工太重要了,就这叫赢在起跑线,一切都不能随便了,别把一个表定义成了降了主建外其它全是Varchar(255)。对数据库的double/float这种字
段做索引时一定要小心。

待思考:
为什么加一个引号后索引长度执行计划变成了258,为什么是258呢,不是别的呢。