TeXmacs
GNU TeXmacs 1.99.8 已发布,这是一个支持各种数学公式的所见即所得编辑器,可以用来编辑文本、图形、数学、交互内容,它的界面非常友好,并且内置高质量的排版引擎。
解释一: 就是select的数据列只用从索引中就能够取得,不必从数据表中读取,换句话说查询列要被所使用的索引覆盖。
解释二: 索引是高效找到行的一个方法,当能通过检索索引就可以读取想要的数据,那就不需要再到数据表中读取行了。如果一个索引包含了(或覆盖了)满足查询语句中字段与条件的数据就叫做覆盖索引。
解释三: 是非聚集组合索引的一种形式,它包括在查询里的Select、Join和Where子句用到的所有列(即建立索引的字段正好是覆盖查询语句[select子句]与查询条件[Where子句]中所涉及的字段,也即,索引包含了查询正在查找的所有数据)。
1 | CREATE TABLE `t_order` ( |
在 order_code 上创建了唯一性索引 uni_order_code
数据条数:32W条
SQL:select order_code, order_amount from t_order order by order_code limit 1000;
执行计划
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t_order ALL NULL NULL NULL NULL 316350 Using filesort
全表扫描、文件排序,注定查询慢!
那为什么MySQL没有利用索引(uni_order_code)扫描完成查询呢?
因为MySQL认为这个场景利用索引扫描并非最优的结果。我们先来看下执行时间,然后再来分析为什么没有利用索引扫描。
如果表数据量继续增长下去,性能会越来越差。
MySQL为什么使用全表扫描、文件排序,而没有使用索引扫描、利用索引顺序?
虽然是全表扫描,但是扫描是顺序的(不管机械硬盘还是 SSD 顺序读写性能都是高的),并且数据量不是特别大,所以这部分消耗的时间应该不是特别大,主要的消耗应该是在排序上。
uni_order_code 是二级索引,索引上保存了(order_code,id),每扫描一条索引需要根据索引上的 id 定位(随机 IO)到数据行上读取order_amount,需要1000次随机IO才能完成查询,而机械硬盘随机 IO 的效率是极低的(机械硬盘每秒寻址几百次)。
既然我们已经知道是因为随机IO导致无法利用索引,那么有没有办法消除随机IO?
解决办法:覆盖索引。
1 | ALTER TABLE `t_order` |
创建了复合索引 idx_ordercode_orderamount(order_code,order_amount),将 select 的列 order_amount 也放到索引中。
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t_order index NULL idx_ordercode_orderamount 42 NULL 1000 Using index
从执行时间来看,SQL 的执行时间提升到原来的 1/20,已经达到我们的预期。
覆盖索引是select的数据列只用从索引中就能够取得,不必读取数据行,换句话说查询列要被所建的索引覆盖。索引的字段不只包含查询列,还包含查询条件、排序等。
要写出性能很好的SQL不仅需要学习SQL,还要能看懂数据库执行计划,了解数据库执行过程、索引的数据结构等。
聚集索引:https://www.cnblogs.com/chillsrc/archive/2012/09/04/2671092.html
MySQL数据库一般都是按照这个步骤去演化的,成本也是由低到高。
对于一个存储设计,必须考虑业务特点,收集的信息如下:
大致明白以上10个问题,至于如何设计此类的大表,应该什么都清楚了!
至于优化若是指创建好的表,不能变动表结构的话,那建议InnoDB引擎,多利用点内存,减轻磁盘IO负载,因为IO往往是数据库服务器的瓶颈。
另外对优化索引结构去解决性能问题的话,建议优先考虑修改类SQL语句,使他们更快些,不得已只靠索引组织结构的方式,当然此话前提是,
索引已经创建的非常好,若是读为主,可以考虑打开query_cache,以及调整一些参数值:sort_buffer_size,read_buffer_size,read_rnd_buffer_size,join_buffer_size
MySQL 数据库设计总结:https://cloud.tencent.com/developer/article/1004367
联合索引的建立原则(以下均假设在数据库表的字段a,b,c上建立联合索引(a,b,c))
合理构造Query语句
背景:有三张表,是5亿的数据,每天张表每天的增量是100w,每张表大概在10个columns左右
当前使用mysiam,没有做分区。在只读情况下,比innodb的效率要高13%左右。
在做了partition之后,读一下mysql的官方文档,其实对于partition,专门是对myisam做的优化,对于innodb,所有的数据是存在ibdata里面的,所以即使你可以看到schema变了,其实没有本质的变化。在分区出于同一个physical disk下面的情况下,提升大概只有1%
在分区在不同的physical disk下,分到了三个不同的disks下,提升大概在3%,其实所谓的吞吐量,由很多因素决定的,比如你的explain parition时候可以看到,record在那一个分区,如果每个分区都有,其实本质上没有解决读的问题,这样只会提升写的效率。
另外一个问题在于,分区,你怎么分,如果一张表,有三个column都是经常被用于做查询条件的,其实是一件很悲惨的事情,因为你没有办法对所有的sql做针对性的分区,如果你只是如mysql官方文档上说的,只对时间做一个分区,而且你也只用时间查询的话,恭喜你。
堆组织表的存储速度因为不用考虑排序,所以存储速度会比较快。但是要查找符合某个条件的记录,就必须得读取全部的记录以便筛选。而这个时候为了加快查询速度,索引就出现了,索引是针对少量特定字段的值拿出来进行排序存储,并记录在表中的位置,而因为索引是有序的,所以就会很容易通过索引查询到具体的记录位置(普遍使用二分查找法),然后再根据记录位置直接从表中读取该记录。同时因为索引的字段较少,所以索引通常会比其基表小得多。
从上面通过索引访问表记录的方式可以看出,当要访问的数据量较大时,通过每一条记录的位置去访问原始记录,每一条符合条件的记录都需要经过索引访问后再访问基表这样一个复杂的过程,这会花费很多时间。同样,如果不经过索引而直接查询表,也可能因为表字段太多,记录较大的情况下把全部的数据读取进来,这也会花费很多时间。
那怎么办呢?这个时候就会想到,如果表中数据本身就是有序的,这样查询表的时候就可以快速的找到符合条件的记录位置,而很容易判断符合条件记录的位置,这样只需要读取一小部分数据出来就可以了,不需要全表记录都读取出来进行判断。索引组织表就这样产生了,当然索引表中插入,更新的时候可能会因为需要排序而将数据重组,这时候数据插入或更新速度会比堆组织表慢一些。如果堆组织表上有索引,那么对堆组织表的插入也会因为要修改索引而变慢。
堆表(heap table)数据插入时时存储位置是随机的,主要是数据库内部块的空闲情况决定,获取数据是按照命中率计算,全表扫表时不见得先插入的数据先查到。
堆表的特点就是索引和数据分开,所有索引都是二级索引,或叫辅助索引。所以主键索引也是二级索引,没有完整记录,区别只有唯一或非唯一。索引中存储的是key与指针,指针指向具体数据记录。当然,查找key的算法都是一样的,使用二分查找,也叫书签查找。
两者的查找方式都一样,通过先找到key,然后定位到数据。不论是通过主键还是二级索引,两者的开销都是一样的。
索引表(IOT)数据存储是把表按照索引的方式存储的,数据是有序的,数据的位置是预先定好的,与插入的顺序没有关系。
索引表的查询效率逼堆表高(相当于查询索引的效率),插入数据的速度比堆表慢。
索引组织表必须要有主键,如果非显式创建,InnoDB存储引擎会默认创建一个ROWID当做主键;而堆表则无强制要求。
这就是经常有文章说MyISAM比InnoDB快的原因吧,但这个说法并不完全正确,索引组织表由于索引项和数据存储在一起,且InnoDB聚集索引各个叶子节点之间都是同过双向链表组织,且都是根据主键逻辑顺序存放,所以无论是基于主键的等值查询还是范围查询都能大大节省磁盘访问时间。
特别对于范围查询,只需要定位到开始key的位置,就可以顺着这个位置扫描到结束key。如下SQL语句:
1 | select * from table where id between 1000 and 2000 |
常见的水平切分方式:分库分表;分区表
把一个很大的库(表)的数据分到几个库(表)中,每个库(表)的结构都相同,但他们可能分布在不同的mysql实例,甚至不同的物理机器上,以达到降低单库(表)数据量,提高访问性能的目的。分库分表往往是业务层实施的,分库分表后,为了满足某些特定业务功能,往往需要rd修改代码。
所有数据还在一个表中,但物理存储根据一定的规则放在不同的文件中。这个是mysql支持的功能,业务rd代码无需改动。
看上去分区表很帅气,为什么大部分互联网还是更多的选择自己分库分表来水平扩展咧?
缺点
优点
原因分析:这个错误是由JVM中的本地代码抛出的. 在真正为数组分配内存之前, JVM会执行一项检查: 要分配的数据结构在该平台是否可以寻址(addressable)。
一般很少看到这个错误, 因为Java使用 int 类型作为数组的下标(index, 索引)。在Java中, int类型的最大值为 2^31 – 1 = 2,147,483,647。大多数平台的限制都约等于这个值,例如在 64位的 MB Pro 上, Java 1.7 平台可以分配长度为 2,147,483,645, 以及 Integer.MAX_VALUE-2) 的数组。
https://hub.docker.com/_/docker
https://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/
组成部分:
1 | UUID.randomUUID().toString() |
举例,生产消费链条: P -> C1 -> C2
假如P生产者一次性生产了1000万条数据,在默认情况下,C1必须消费完这1000万条数据后,C2才能继续接着处理这1000万条数据,在实际情况中,这是不合理的。
1 | private void processEvents() { |
在这段代码中,只有当前一个消费者调用了 sequence.set(availableSequence) 后,下一个消费者才能接着消费数据。
The call to sequence.set() is placed at the end of the callback to provide the maximum possible throughput.
The call to Sequence.set() is reasonably cheap but not as fast as a standard variable assignment as it requires atomicity and enforces ordering. However the use case that you mention is a common one therefore we have a specific type of event handler for it.
If you want to have an event handler that updates the sequence more frequently that the default, then you should use the SequenceReportingEventHandler.
1 | public class MyHandler implements SequenceReportingEventHandler<Data> { |