1 2 3 4 5 6 |
//使用File获取resources里面资源文件的相对路径 若文件名称为中文可能会报文件不存在 File file = new File(this.getClass().getResource("/province-city.josn").getPath()); //使用inputStream InputStream inputStream = this.getClass().getResourceAsStream("/province-city.json"); |
from:https://www.cnblogs.com/yang-xiansen/p/13529568.html
View DetailsERROR in xxx.js from UglifyJs 问题 ERROR in app.bundle.js from UglifyJs Unexpected token: name «element», expected: punc «;» [app.bundle.js:106,8] 在用webpack对代码打包的时候报错,在网上找到了类似的答案,还是没有解决我的问题. 能解决大部分问题的链接 https://stackoverflow.com/questions/41254538/error-in-bundle-js-from-uglifyjs http://www.cnblogs.com/aredleave/p/7586911.html https://segmentfault.com/a/1190000011212544 按照以上方法对环境进行重新配置,依然报错!
1 2 3 4 |
ERROR in ./src/index.js Module build failed (from ./node_modules/babel-loader/lib/index.js): Error: Cannot find module '@babel/core' babel-loader@8 requires Babel 7.x (the package '@babel/core'). If you'd like to use Babel 6.x ('babel-core'), you should install 'babel-loader@7'. |
报错原因 通过代码报错原因是 babel-loader 版本问题,因为 babel-loader 用的最新的版本,和 UglifyJs 不兼容. 解决方法 通过运行下面代码对babel-loader进行重新安装(低版本). npm install --save-dev babel-loader@7 通过修改后的package.json配置文件,亲测可以正确打包,无报错现象.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
{ "name": "kankan", "version": "1.0.0", "description": "kankan", "main": "webpack.config.js", "scripts": { "start": "webpack-dev-server --open --config webpack.dev.js", "build": "webpack --config webpack.prod.js" }, "author": "kankan", "license": "ISC", "devDependencies": { "babel": "^6.23.0", "babel-core": "^6.26.3", "babel-loader": "^7.1.5", "babel-preset-es2015": "^6.24.1", "clean-webpack-plugin": "^2.0.1", "css-loader": "^2.1.1", "express": "^4.16.4", "html-webpack-plugin": "^3.2.0", "style-loader": "^0.23.1", "uglifyjs-webpack-plugin": "^2.1.2", "webpack": "^4.30.0", "webpack-cli": "^3.3.1", "webpack-dev-middleware": "^3.6.2", "webpack-dev-server": "^3.3.1", "webpack-manifest-plugin": "^2.0.4", "webpack-merge": "^4.2.1" } } |
奇卡奇卡 哈哈哈 个人主页:https://kankan.fun from:https://blog.csdn.net/qq_38025939/article/details/89576282
View DetailsDocker提供了重新启动策略 来控制容器在退出时或Docker重新启动时是否自动启动。重新启动策略可确保以正确的顺序启动链接的容器。Docker建议您使用重新启动策略,并避免使用进程管理器来启动容器。 重新启动策略--live-restore与dockerd 命令的标志不同。--live-restore尽管网络和用户输入中断,但使用允许您在Docker升级期间保持容器运行。 使用重启策略 要为容器配置重新启动策略,请--restart在使用该docker run命令时使用该标志。--restart标志的值可以是以下任何一种: 旗 描述 no 不要自动重启容器。(默认) on-failure 如果容器由于错误而退出,则重新启动容器,该错误表现为非零退出代码。 always 如果容器停止,请务必重启容器。如果手动停止,则仅在Docker守护程序重新启动或手动重新启动容器本身时才重新启动。(参见重启政策详情中列出的第二个项目) unless-stopped 类似于always,除了当容器停止(手动或其他方式)时,即使在Docker守护程序重新启动后也不会重新启动容器。 以下示例启动Redis容器并将其配置为始终重新启动,除非明确停止或重新启动Docker。
1 |
$ docker run -dit --restart unless-stopped redis |
重启政策详情 使用重启策略时请记住以下几点: 重启策略仅在容器成功启动后生效。在这种情况下,成功启动意味着容器启动至少10秒并且Docker已开始监视它。这可以防止根本不启动的容器进入重启循环。 如果手动停止容器,则会忽略其重新启动策略,直到Docker守护程序重新启动或手动重新启动容器。这是防止重启循环的另一种尝试。 重新启动策略仅适用于容器。群组服务的重新启动策略配置不同。请参阅与服务重新启动相关的 标志。 如果run时没有添加restart 可以通过update命令追加 docker update --restart=always web 1、先后台启动容器未加restart参数 2、docker ps 查看了当前运行的容器 3、重启docker 服务 4、再次docker ps 查看当前运行的容器,发现容器并没有运行 5、利用 update 设置 restart=always 6、重启docker 服务 7、再次docker ps 查看当前运行的容器,此时发现已经自动启动容器 ——————— 使用流程管理器 如果重新启动策略不适合您的需要,例如当Docker之外的进程依赖Docker容器时,您可以使用流程管理器,例如 upstart, systemd或supervisor。 警告:不要尝试将Docker重新启动策略与主机级进程管理器结合使用,因为这会产生冲突。 要使用进程管理器,请将其配置为使用您通常用于手动启动容器的相同docker start或docker service命令来启动容器或服务。有关更多详细信息,请参阅特定流程管理器的文档。 在容器内使用进程管理器 进程管理器也可以在容器内运行,以检查进程是否正在运行,如果没有则启动/重启进程 官方介绍在此,以上内容引用官网内容 https://docs.docker.com/engine/admin/start-containers-automatically/#use-a-process-manager from:https://www.cnblogs.com/wei9593/p/11192908.html
View Details从AMQP协议可以看出,MessageQueue、Exchange和Binding构成了AMQP协议的核心,下面我们就围绕这三个主要组件 从应用使用的角度全面的介绍如何利用Rabbit MQ构建消息队列以及使用过程中的注意事项。 1. 声明MessageQueue 在Rabbit MQ中,无论是生产者发送消息还是消费者接受消息,都首先需要声明一个MessageQueue。这就存在一个问题,是生产者声明还是消费者声明呢?要解决这个问题,首先需要明确: a)消费者是无法订阅或者获取不存在的MessageQueue中信息。 b)消息被Exchange接受以后,如果没有匹配的Queue,则会被丢弃。 在明白了上述两点以后,就容易理解如果是消费者去声明Queue,就有可能会出现在声明Queue之前,生产者已发送的消息被丢弃的隐患。如果应用能够通过消息重发的机制允许消息丢失,则使用此方案没有任何问题。但是如果不能接受该方案,这就需要无论是生产者还是消费者,在发送或者接受消息前,都需要去尝试建立消息队列。这里有一点需要明确,如果客户端尝试建立一个已经存在的消息队列,Rabbit MQ不会做任何事情,并返回客户端建立成功的。 如果一个消费者在一个信道中正在监听某一个队列的消息,Rabbit MQ是不允许该消费者在同一个channel去声明其他队列的。Rabbit MQ中,可以通过queue.declare命令声明一个队列,可以设置该队列以下属性: a) Exclusive:排他队列,如果一个队列被声明为排他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除。这里需要注意三点:其一,排他队列是基于连接可见的,同一连接的不同信道是可以同时访问同一个连接创建的排他队列的。其二,“首次”,如果一个连接已经声明了一个排他队列,其他连接是不允许建立同名的排他队列的,这个与普通队列不同。其三,即使该队列是持久化的,一旦连接关闭或者客户端退出,该排他队列都会被自动删除的。这种队列适用于只限于一个客户端发送读取消息的应用场景。 b) Auto-delete:自动删除,如果该队列没有任何订阅的消费者的话,该队列会被自动删除。这种队列适用于临时队列。 c) Durable:持久化,这个会在后面作为专门一个章节讨论。 d) 其他选项,例如如果用户仅仅想查询某一个队列是否已存在,如果不存在,不想建立该队列,仍然可以调用queue.declare,只不过需要将参数passive设为true,传给queue.declare,如果该队列已存在,则会返回true;如果不存在,则会返回Error,但是不会创建新的队列。 2. 生产者发送消息 在AMQP模型中,Exchange是接受生产者消息并将消息路由到消息队列的关键组件。ExchangeType和Binding决定了消息的路由规则。所以生产者想要发送消息,首先必须要声明一个Exchange和该Exchange对应的Binding。可以通过 ExchangeDeclare和BindingDeclare完成。在Rabbit MQ中,声明一个Exchange需要三个参数:ExchangeName,ExchangeType和Durable。ExchangeName是该Exchange的名字,该属性在创建Binding和生产者通过publish推送消息时需要指定。ExchangeType,指Exchange的类型,在RabbitMQ中,有三种类型的Exchange:direct ,fanout和topic,不同的Exchange会表现出不同路由行为。Durable是该Exchange的持久化属性,这个会在消息持久化章节讨论。声明一个Binding需要提供一个QueueName,ExchangeName和BindingKey。下面我们就分析一下不同的ExchangeType表现出的不同路由规则。 生产者在发送消息时,都需要指定一个RoutingKey和Exchange,Exchange在接到该RoutingKey以后,会判断该ExchangeType: a) 如果是Direct类型,则会将消息中的RoutingKey与该Exchange关联的所有Binding中的BindingKey进行比较,如果相等,则发送到该Binding对应的Queue中。 b) 如果是 Fanout 类型,则会将消息发送给所有与该 Exchange 定义过 Binding 的所有 Queues 中去,其实是一种广播行为。 c)如果是Topic类型,则会按照正则表达式,对RoutingKey与BindingKey进行匹配,如果匹配成功,则发送到对应的Queue中。 3. 消费者订阅消息 在RabbitMQ中消费者有2种方式获取队列中的消息: a) 一种是通过basic.consume命令,订阅某一个队列中的消息,channel会自动在处理完上一条消息之后,接收下一条消息。(同一个channel消息处理是串行的)。除非关闭channel或者取消订阅,否则客户端将会一直接收队列的消息。 b) 另外一种方式是通过basic.get命令主动获取队列中的消息,但是绝对不可以通过循环调用basic.get来代替basic.consume,这是因为basic.get RabbitMQ在实际执行的时候,是首先consume某一个队列,然后检索第一条消息,然后再取消订阅。如果是高吞吐率的消费者,最好还是建议使用basic.consume。 如果有多个消费者同时订阅同一个队列的话,RabbitMQ是采用循环的方式分发消息的,每一条消息只能被一个订阅者接收。例如,有队列Queue,其中ClientA和ClientB都Consume了该队列,MessageA到达队列后,被分派到ClientA,ClientA服务器收到响应,服务器删除MessageA;再有一条消息MessageB抵达队列,服务器根据“循环推送”原则,将消息会发给ClientB,然后收到ClientB的确认后,删除MessageB;等到再下一条消息时,服务器会再将消息发送给ClientA。 这里我们可以看出,消费者再接到消息以后,都需要给服务器发送一条确认命令,这个即可以在handleDelivery里显示的调用basic.ack实现,也可以在Consume某个队列的时候,设置autoACK属性为true实现。这个ACK仅仅是通知服务器可以安全的删除该消息,而不是通知生产者,与RPC不同。 如果消费者在接到消息以后还没来得及返回ACK就断开了连接,消息服务器会重传该消息给下一个订阅者,如果没有订阅者就会存储该消息。 既然RabbitMQ提供了ACK某一个消息的命令,当然也提供了Reject某一个消息的命令。当客户端发生错误,调用basic.reject命令拒绝某一个消息时,可以设置一个requeue的属性,如果为true,则消息服务器会重传该消息给下一个订阅者;如果为false,则会直接删除该消息。当然,也可以通过ack,让消息服务器直接删除该消息并且不会重传。 4. 持久化: Rabbit MQ默认是不持久队列、Exchange、Binding以及队列中的消息的,这意味着一旦消息服务器重启,所有已声明的队列,Exchange,Binding以及队列中的消息都会丢失。通过设置Exchange和MessageQueue的durable属性为true,可以使得队列和Exchange持久化,但是这还不能使得队列中的消息持久化,这需要生产者在发送消息的时候,将delivery mode设置为2,只有这3个全部设置完成后,才能保证服务器重启不会对现有的队列造成影响。这里需要注意的是,只有durable为true的Exchange和durable为ture的Queues才能绑定,否则在绑定时,RabbitMQ都会抛错的。持久化会对RabbitMQ的性能造成比较大的影响,可能会下降10倍不止。 5. 事务: 对事务的支持是AMQP协议的一个重要特性。假设当生产者将一个持久化消息发送给服务器时,因为consume命令本身没有任何Response返回,所以即使服务器崩溃,没有持久化该消息,生产者也无法获知该消息已经丢失。如果此时使用事务,即通过txSelect()开启一个事务,然后发送消息给服务器,然后通过txCommit()提交该事务,即可以保证,如果txCommit()提交了,则该消息一定会持久化,如果txCommit()还未提交即服务器崩溃,则该消息不会服务器就收。当然Rabbit MQ也提供了txRollback()命令用于回滚某一个事务。 6. Confirm机制: 使用事务固然可以保证只有提交的事务,才会被服务器执行。但是这样同时也将客户端与消息服务器同步起来,这背离了消息队列解耦的本质。Rabbit MQ提供了一个更加轻量级的机制来保证生产者可以感知服务器消息是否已被路由到正确的队列中——Confirm。如果设置channel为confirm状态,则通过该channel发送的消息都会被分配一个唯一的ID,然后一旦该消息被正确的路由到匹配的队列中后,服务器会返回给生产者一个Confirm,该Confirm包含该消息的ID,这样生产者就会知道该消息已被正确分发。对于持久化消息,只有该消息被持久化后,才会返回Confirm。Confirm机制的最大优点在于异步,生产者在发送消息以后,即可继续执行其他任务。而服务器返回Confirm后,会触发生产者的回调函数,生产者在回调函数中处理Confirm信息。如果消息服务器发生异常,导致该消息丢失,会返回给生产者一个nack,表示消息已经丢失,这样生产者就可以通过重发消息,保证消息不丢失。Confirm机制在性能上要比事务优越很多。但是Confirm机制,无法进行回滚,就是一旦服务器崩溃,生产者无法得到Confirm信息,生产者其实本身也不知道该消息吃否已经被持久化,只有继续重发来保证消息不丢失,但是如果原先已经持久化的消息,并不会被回滚,这样队列中就会存在两条相同的消息,系统需要支持去重。 其他: Broker:简单来说就是消息队列服务器实体。 Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。 Queue:消息队列载体,每个消息都会被投入到一个或多个队列。 Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来。 Routing Key:路由关键字,exchange根据这个关键字进行消息投递。 vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。 producer:消息生产者,就是投递消息的程序。 consumer:消息消费者,就是接受消息的程序。 channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。 消息队列的使用过程大概如下: (1)客户端连接到消息队列服务器,打开一个channel。 (2)客户端声明一个exchange,并设置相关属性。 (3)客户端声明一个queue,并设置相关属性。 (4)客户端使用routing key,在exchange和queue之间建立好绑定关系。 (5)客户端投递消息到exchange。 Exchanges, queues, and bindings […]
View Detailsvue-cli构建项目使用sass报错 Module build failed: TypeError: this.getOptions is not a function 出现问题的原因是安装的sass-loader版本过高,选择安装较低版本的sass-loader即可。
1 |
npm install sass-loader@7.3.1 --save-dev |
Module build failed: Error: Node Sass version 6.0.1 is incompatible with ^4.0.0. 出现问题的原因是安装的sass版本过高,选择安装4.0+版本的sass即可。
1 |
npm install node-sass@4.14.1 --save-dev |
from:https://www.cnblogs.com/chenjy1225/p/14930870.html
View Details最近在学习vue框架,使用webpack打包vue项目,在执行npm run start的时候 出现如下错误: This dependency was not found: * !!vue-style-loader!css-loader?{"minimize":false,"sourceMap":false}!../../node_modules/vue-loader/lib/style-compiler/index?{"vue":true,"id":"data-v-1d57e5ea","scoped":false,"hasInlineConfig":false}!stylus-loader?{"sourceMap":false}!../../node_modules/vue-loader/lib/selector?type=styles&index=0!./a.vue in ./src/components/a.vue To install it, you can run: npm install --save !!vue-style-loader!css-loader?{"minimize":false,"sourceMap":false}!../../node_modules/vue-loader/lib/style-compiler/index?{"vue":true,"id":"data-v-1d57e5ea","scoped":false,"hasInlineConfig":false}!stylus-loader?{"sourceMap":false}!../../node_modules/vue-loader/lib/selector?type=styles&index=0!./a.vu 解决思路: npm install sass-loader --save; npm install node-sass --save; 然后运行npm run start就可以 from:https://www.cnblogs.com/hexiaobao/p/8260858.html
View Details重新Rubuild Project 停止在 运行时错误: 试着的解决方式 运行clean 、install 、运行。 运行正常!! 解决方法 删除 .idea ,重新打开项目 ,重新建立工程Rebuild Project ,信息如下: java: /E:/JPADemo/src/main/java/com/example/jpademo/JpaDemoApplication.java使用了未经检查或不安全的操作。 要取消这种告警信息,可在 public class JpaDemoApplication 类面前加@SuppressWarnings("unchecked") 原因:JAVA是一门安全性比较高的语言,它在编译之类要进行类型等一系列的检查。如果你使用了注解就可以告诉编译器不用检查,这样子就可以避过编译时期间的安全检查,这样子的效率会提高 。但同时 安全性就大打折扣了。 但是运行正常!! from:https://www.cnblogs.com/wfy680/p/15014376.html
View Details使用IntelliJ IDEA开发groovy,创建一个项目进入到这个界面: 如果Groovy. library是no. library select 那就点击右侧的create按钮,选择你安装的groovy目录就可以, 如果IntelliJ IDEA 左侧没有Groovy选项的话那就安装groovy插件, 新建的groovy项目是这样的: 会发现并不是像我们Android 在studio下创建项目一样有一个默认的MainActivity,groovy是没有的,那么从事编程开发的入门都是从hello world开始的,那么现在创建一个hello.groovy文件
1 2 3 4 5 6 7 8 9 |
class Hello { public static void main(String[] args){ print("hello world groovy") } } |
这是我们创建的第一个类Hello.groovy 从上面的代码就可以提现出groovy是完全支持Java的 而且更方便的是我们在控制台输入一句话 直接使用println()方法就行,相当于Java中的静态导包功能. 还有更神奇的写法: 是不是groovy很强大 这个写法和上面的Java中的写法结果是一样的.如果想弄懂gradle 构建是有必须去学习下. from:https://blog.csdn.net/coderinchina/article/details/89600861
View Details前几天统计一个sql,是一个人提交了多少工单,顺便做了相关sql优化。数据大概2000多w。
1 2 3 |
select CustName,count(1) c from WorkOrder where CreateDate>'2016-5-1' and CreateDate<'2017-1-1' group by CustName having c>100 order by c desc; |
为了实验最少受其他因素干扰,将生产库的200多w数据导出来,用测试服务器进行测试。 导出来的数据是一个堆表,没有主键,没有索引。
1 2 3 4 5 |
mysql> show index from WorkOrder; 查询index方法1 Empty set (0.00 sec) mysql> show keys from WorkOrder; 查询index方法2 Empty set (0.00 sec) |
1.堆表的情况 这时候就在这时候,用执行计划分析下语句。
1 2 3 4 5 6 7 8 |
mysql> explain select CustName,count(1) c from WorkOrder where CreateDate>'2016-5-1' and CreateDate<'2017-1-1' group by CustName having c>100 order by c desc; +----+-------------+-----------+------+---------------+------+---------+------+---------+----------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+------+---------------+------+---------+------+---------+----------------------------------------------+ | 1 | SIMPLE | WorkOrder | ALL | NULL | NULL | NULL | NULL | 2528727 | Using where; Using temporary; Using filesort | +----+-------------+-----------+------+---------------+------+---------+------+---------+----------------------------------------------+ 1 row in set |
select_type的值为SIMPLE,表示简单的select查询,不使用union或子查询。 type的值为ALL,表示要对表进行表扫描。 possible_keys 表示能使用哪个索引找到行记录。 key 表示Mysql决定使用的索引(键)。 key_len 表示Mysql决定使用索引的长度。 ref 表示使用哪个列和key一起从表中选择行。 rows 表示Mysql认为它执行查询时必须检查的行数。 extra 表示查询的详情信息,用到where,临时表,排序。 执行下该语句三次,发现执行了16.30 sec、16.34 sec、16.24 sec。 2.有索引的情况 建了四个索引,分别以custname,CreateDate建两个单列索引,另外两个是联合索引,只是最左边列不一样。
1 2 3 4 |
alter table WorkOrder add index ix_name(custname) alter table WorkOrder add index ix_date(CreateDate) alter table WorkOrder add index ix_namedate(custname,CreateDate) alter table WorkOrder add index ix_datename(CreateDate,custname) |
1 2 3 4 5 6 7 8 9 10 11 12 |
mysql> show keys from WorkOrder; +-----------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +-----------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | WorkOrder | 1 | ix_name | 1 | CustName | A | 1264363 | NULL | NULL | YES | BTREE | | | | WorkOrder | 1 | ix_date | 1 | CreateDate | A | 2528727 | NULL | NULL | | BTREE | | | | WorkOrder | 1 | ix_namedate | 1 | CustName | A | 1264363 | NULL | NULL | YES | BTREE | | | | WorkOrder | 1 | ix_namedate | 2 | CreateDate | A | 2528727 | NULL | NULL | | BTREE | | | | WorkOrder | 1 | ix_datename | 1 | CreateDate | A | 2528727 | NULL | NULL | | BTREE | | | | WorkOrder | 1 | ix_datename | 2 | CustName | A | 2528727 | NULL | NULL | YES | BTREE | | | +-----------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 6 rows in set (0.00 sec) |
之后,用执行计划分析下sql查询语句。
1 2 3 4 5 6 7 8 |
mysql> explain select CustName,count(1) c from WorkOrder where CreateDate>'2016-5-1' and CreateDate<'2017-1-1' group by CustName having c>100 order by c desc; +----+-------------+-----------+-------+-----------------------------------------+-------------+---------+------+--------+-----------------------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+-------+-----------------------------------------+-------------+---------+------+--------+-----------------------------------------------------------+ | 1 | SIMPLE | WorkOrder | range | ix_name,ix_date,ix_namedate,ix_datename | ix_datename | 4 | NULL | 824372 | Using where; Using index; Using temporary; Using filesort | +----+-------------+-----------+-------+-----------------------------------------+-------------+---------+------+--------+-----------------------------------------------------------+ 1 row in set (0.01 sec) |
从执行计划可以看出,Mysql从四个索引中选取了ix_datename这个索引,type为range表示索引范围扫描。rows的数量值是没堆表的1/3。 执行语句三次,时间是 8.64 sec、8.61sec、8.55 sec。 我建了三个索引,那么我想用下另外三个索引怎么办? 这里可以用force index(),这个指令可以指定本次查询强制使用哪个索引,因为Mysql优化器的选择并不是最优的索引。
1 2 3 4 5 6 |
mysql> explain select CustName,count(1) c from WorkOrder force index(ix_namedate) where CreateDate>'2016-5-1' and CreateDate<'2017-1-1' group by CustName having c>100 order by c desc; +----+-------------+-----------+-------+---------------------------------+-------------+---------+------+---------+-----------------------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+-------+---------------------------------+-------------+---------+------+---------+-----------------------------------------------------------+ | 1 | SIMPLE | WorkOrder | index | ix_name,ix_namedate,ix_datename | ix_namedate | 307 | NULL | 2528727 | Using where; Using index; Using temporary; Using filesort | +----+-------------+-----------+-------+---------------------------------+-------------+---------+------+---------+-----------------------------------------------------------+ |
选用另一个联合索引 ix_namedate,这次type变为index,可以这样理解,根据索引的顺序进行全表扫描,比ALL效率要高些,rows的值和堆表的值差不多。 执行语句三次,时间是 7.84 sec、7.92 sec、7.84 sec。
1 2 3 4 5 6 7 8 |
mysql> explain select CustName,count(1) c from WorkOrder force index(ix_name) where CreateDate>'2016-5-1' and CreateDate<'2017-1-1' group by CustName having c>100 order by c desc; +----+-------------+-----------+-------+---------------------------------+---------+---------+------+---------+----------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+-------+---------------------------------+---------+---------+------+---------+----------------------------------------------+ | 1 | SIMPLE | WorkOrder | index | ix_name,ix_namedate,ix_datename | ix_name | 303 | NULL | 2528727 | Using where; Using temporary; Using filesort | +----+-------------+-----------+-------+---------------------------------+---------+---------+------+---------+----------------------------------------------+ 1 row in set |
选用另一个联合索引 ix_name,这次type是index,可以这样理解,根据索引的顺序进行全表扫描,比ALL效率要高些,rows的值和堆表的值差不多。 执行语句三次,时间是 1 min 28.17 sec、1 min 27.64 sec、1 min 27.58 sec。
1 2 3 4 5 6 7 |
mysql> explain select CustName,count(1) c from WorkOrder force index(ix_date) where CreateDate>'2016-5-1' and CreateDate<'2017-1-1' group by CustName having c>100 order by c desc; +----+-------------+-----------+-------+-----------------------------------------+---------+---------+------+--------+-------------------------------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+-------+-----------------------------------------+---------+---------+------+--------+-------------------------------------------------------------------+ | 1 | SIMPLE | WorkOrder | range | ix_name,ix_date,ix_namedate,ix_datename | ix_date | 4 | NULL | 921062 | Using index condition; Using MRR; Using temporary; Using filesort | +----+-------------+-----------+-------+-----------------------------------------+---------+---------+------+--------+-------------------------------------------------------------------+ |
选用另一个联合索引 ix_date,这次type是range,表示索引范围扫描,rows的值是堆表的1/3多些 。 执行语句三次,时间是 9.55 sec、9.52 sec、9.39 sec。 假如我不想用索引了怎么办? 可以使用ignore index(),这个指令可以强制Mysql在查询时,不使用某索引。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
mysql> explain select CustName,count(1) c from WorkOrder ignore index(ix_date) where CreateDate>'2016-5-1' and CreateDate<'2017-1-1' group by CustName having c>100 order by c desc; +----+-------------+-----------+-------+---------------------------------+-------------+---------+------+--------+-----------------------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+-------+---------------------------------+-------------+---------+------+--------+-----------------------------------------------------------+ | 1 | SIMPLE | WorkOrder | range | ix_name,ix_namedate,ix_datename | ix_datename | 4 | NULL | 824372 | Using where; Using index; Using temporary; Using filesort | +----+-------------+-----------+-------+---------------------------------+-------------+---------+------+--------+-----------------------------------------------------------+ mysql> explain select CustName,count(1) c from WorkOrder ignore index(ix_date,ix_name,ix_namedate,ix_datename) where CreateDate>'2016-5-1' and CreateDate<'2017-1-1' group by CustName having c>100 order by c desc; +----+-------------+-----------+------+---------------------------------+------+---------+------+---------+----------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-----------+------+---------------------------------+------+---------+------+---------+----------------------------------------------+ | 1 | SIMPLE | WorkOrder | ALL | ix_name,ix_namedate,ix_datename | NULL | NULL | NULL | 2528727 | Using where; Using temporary; Using filesort | +----+-------------+-----------+------+---------------------------------+------+---------+------+---------+----------------------------------------------+ |
上面第一个强制不使用ix_date索引,那么就Mysql就从剩下的三个索引中,选取他认为是最优的索引。第二个时将四个索引都不使用,那么Mysql就进行全表扫描了。 总结: 1.Mysql的语句优化,没有绝对的正确,explain也只是给出个大致的方向,例如 key_len值小的,rows小的按理说,时间应该最短,效率最高。但是,实验中时间最少的却不是那个值最小的。 2. 优化还需根据实际数据情况,例如,假如我where选取的时间范围变化,或者说CustName的分布有些变化,可能跟刚才的实验,又会产生一定偏差。 3. 同样我还实验了,当给表加上主键时,整体的查询时间会缩短些。 […]
View Details