MySQL性能优化浅析及线上案例

作者:京东健康 孟飞

1、 数据库性能优化的意义

业务发展初期,数据库中量一般都不高,也不太容易出一些性能问题或者出的问题也不大,但是当数据库的量级达到一定规模之后,如果缺失有效的预警、监控、处理等手段则会对用户的使用体验造成影响,严重的则会直接导致订单、金额直接受损,因而就需要时刻关注数据库的性能问题。

2、 性能优化的几个常见措施

数据库性能优化的常见手段有很多,比如添加索引、分库分表、优化连接池等,具体如下:

序号 类型 措施 说明
1 物理级别 提升硬件性能 将数据库安装到更高配置的服务器上会有立竿见影的效果,例如提高CPU配置、增加内存容量、采用固态硬盘等手段,在经费允许的范围可以尝试。
2 应用级别 连接池参数优化 我们大部分的应用都是使用连接池来托管数据库的连接,但是大部分都是默认的配置,因而配置好超时时长、连接池容量等参数就显得尤为重要。 1、 如果链接长时间被占用,新的请求无法获取到新的连接,就会影响到业务。 2、 如果连接数设置的过小,那么即使硬件资源没问题,也无法发挥其功效。之前公司做过一些压测,但就是死活不达标,最后发现是由于连接数太小。
3 单表级别 合理运用索引 如果数据量较大,但是又没有合适的索引,就会拖垮整个性能,但是索引是把双刃剑,并不是说索引越多越好,而是要根据业务的需要进行适当的添加和使用。 缺失索引、重复索引、冗余索引、失控索引这几类情况其实都是对系统很大的危害。
4 库表级别 分库分表 当数据量较大的时候,只使用索引就意义不大了,需要做好分库分表的操作,合理的利用好分区键,例如按照用户ID、订单ID、日期等维度进行分区,可以减少扫描范围。
5 监控级别 加强运维 针对线上的一些系统还需要进一步的加强监控,比如订阅一些慢SQL日志,找到比较糟糕的一些SQL,也可以利用业务内一些通用的工具,例如druid组件等。

3、 MySQL底层架构

首先了解一下数据的底层架构,也有助于我们做更好优化。

一次查询请求的执行过程

我们重点关注第二部分和第三部分,第二部分其实就是Server层,这层主要就是负责查询优化,制定出一些执行计划,然后调用存储引擎给我们提供的各种底层基础API,最终将数据返回给客户端。

4、MySQL索引构建过程

目前比较常用的是InnoDB存储引擎,本文讨论也是基于InnoDB引擎。我们一直说的加索引,那到底什么是索引、索引又是如何形成的呢、索引又如何应用呢?这个话题其实很大也很小,说大是因为他底层确实很复杂,说小是因为在大部分场景下程序员只需要添加索引就好,不太需要了解太底层原理,但是如果了解不透彻就会引发线上问题,因而本文平衡了大家的理解成本和知识深度,有一定底层原理介绍,但是又不会太过深入导致难以理解。

首先来做个实验:

创建一个表,目前是只有一个主键索引

CREATE TABLE t1(

a int NOT NULL,

b int DEFAULT NULL,

c int DEFAULT NULL,

d int DEFAULT NULL,

e varchar(20) DEFAULT NULL,

PRIMARYKEY(a)

)ENGINE=InnoDB

插入一些数据:

insert into test.t1 values(4,3,1,1,'d');

insert into test.t1 values(1,1,1,1,'a');

insert into test.t1 values(8,8,8,8,'h');

insert into test.t1 values(2,2,2,2,'b');

insert into test.t1 values(5,2,3,5,'e');

insert into test.t1 values(3,3,2,2,'c');

insert into test.t1 values(7,4,5,5,'g');

insert into test.t1 values(6,6,4,4,'f');

MYSQL从磁盘读取数据到内存是按照一页读取的,一页默认是16K,而一页的格式大概如下。

每一页都包括了这么几个内容,首先是页头、其次是页目录、还有用户数据区域。

1)刚才插入的几条数据就是放到这个用户数据区域的,这个是按照主键依次递增的单向链表。

2)页目录这个是用来指向具体的用户数据区域,因为当用户数据区域的数据变多的时候也就会形成分组,而页目录就会指向不同的分组,利用二分查找可以快速的定位数据。

当数据量变多的时候,那么这一页就装不下这么多数据,就要分裂页,而每页之间都会双向链接,最终形成一个双向链表。

页内的单向链表是为了查找快捷,而页间的双向链表是为了在做范围查询的时候提效,下图为示意图,其中其二页和第三页是复制的第一页,并不真实。

而如果数据还继续累加,光这几个页也不够了,那就逐步的形成了一棵树,也就是说索引B-Tree是随着数据的积累逐步构建出来的。

最下边的一层叫做叶子节点,上边的叫做内节点,而叶子节点中存储的是全量数据,这样的树就是聚簇索引。一直有同学的理解是说索引是单独一份而数据是一份,其实MySQL中有一个原则就是数据即索引、索引即数据,真实的数据本身就是存储在聚簇索引中的,所谓的回表就是回的聚簇索引

但是我们也不一定每次都按照主键来执行SQL语句,大部分情况下都是按照一些业务字段来,那就会形成别的索引树,例如,如果按照b,c,d来创建的索引就会长这样。

推荐1个网站,可以可视化的查看一些算法原型:

目录:

http://www.cs.usfca.edu/~galles/visualization/Algorithms.html

B+树

http://www.cs.usfca.edu/~galles/visualization/BPlusTree.html

而在MySQL官网上介绍的索引的叶子节点是双向链表。

关于索引结构的小结:

对于B-Tree而言,叶子节点是没有链接的,而B+Tree索引是单向链表,但是MySQL在B+Tree的基础之上加以改进,形成了双向链表,双向的好处是在处理> <,between and等'范围查询'语法时可以得心应手。

5、MySQL索引的一些使用规范

1、 只为用于搜索、排序或分组的列创建索引。

重点关注where语句后边的情况

2、 当列中不重复值的个数在总记录条数中的占比很大时,才为列建立索引。

例如手机号、用户ID、班级等,但是比如一张全校学生表,每条记录是一名学生,where语句是查询所有’某学校‘的学生,那么其实也不会提高性能。

3、 索引列的类型尽量小。

无论是主键还是索引列都尽量选择小的,如果很大则会占据很大的索引空间。

4、 可以只为索引列前缀创建索引,减少索引占用的存储空间。

alter table single_table add index idx_key1(key1(10))

5、 尽量使用覆盖索引进行查询,以避免回表操作带来的性能损耗。

select key1 from single_table order by key1

6、 为了尽可能的少的让聚簇索引发生页面分裂的情况,建议让主键自增。

7、 定位并删除表中的冗余和重复索引。

冗余索引:

单列索引:(字段1)

联合索引:(字段1 字段2)

重复索引:

在一个字段上添加了普通索引、唯一索引、主键等多个索引

6、 执行计划

其中常用的是:

possible_keys: 可能用到的索引

key: 实际使用的索引

rows:预估的需要读取的记录条数

7、 线上案例

案例1:

在建设互联网医院系统中,问诊单表当时量级23万左右,其中有一个business_id字符串字段,这个字段用来记录外部订单的ID,并且在该字段上也加了索引,但是'根据该ID查询详情'的SQL语句却总是时好时坏,性能不稳定,快则10ms,慢则2秒左右,SQL大体如下:

select 字段1、字段2、字段3 from nethp_diag where business_Id = ?

因为business_id是记录第三方系统的订单ID,为了兼容不同的第三方系统,因而设计成了字符串类型,但如果传入的是一个数字类型是无法使用索引的,因为MySQL只能将字符串转数字,而不能将数字转字符串,由于外部的ID有的是数字有的是字符串,因而导致索引一会可以走到,一会走不到,最终导致了性能的不稳定。

案例2:

在某次大促的当天,突然接到DBA运维的报警,说数据库突然流量激增,CPU也打到100%了,影响了部分线上功能和体验,遇到这种情况当时大部分人都比较紧张,下图为当时的数据库流量情况:

相关SQL语句:

当时的索引情况

当时的执行计划

其实在patientId和doctor_pin两个字段上是有索引的,但是由于线上情况的改变,导致test判断没有进入,这样的通用查询导致这两个字段没有设置上,进而导致了数据库扫描的量激增,对数据库产生了很大压力。

案例3:

2020年某日上午收到数据库CPU异常报警,对线上有一定的影响,后续检查数据库CPU情况如下,从7点51分开始,CPU从8%瞬间达到99.92%,丝毫没有给程序员留任何情面。

当时的SQL语句:

select rx_id, rx_create_time from nethp_rx_info where rx_status = 5 and status = 1 and rx_product_type = 0 and (parent_rx_id = 0 or parent_rx_id is null) and business_type != 7 and vender_id = 8888 order by rx_create_time asc limit 1;

当时的索引情况:

PRIMARY KEY (id), UNIQUE KEY uniq_rx_id (rx_id), KEY idx_diag_id (diag_id), KEY idx_doctor_pin (doctor_pin) USING BTREE, KEY idx_rx_storeId (store_id), KEY idx_parent_rx_id (parent_rx_id) USING BTREE, KEY idx_rx_status (rx_status) USING BTREE, KEY idx_doctor_status_type (doctor_pin, rx_status, rx_type), KEY idx_business_store (business_type, store_id), KEY idx_doctor_pin_patientid (patient_id, doctor_pin) USING BTREE, KEY idx_rx_create_time (rx_create_time)

当时这张表量级2000多万,而当这条慢SQL执行较少的时候,数据库的CPU也就下来了,恢复到了49.91%,基本可以恢复线上业务,从而表象就是线上间歇性的一会可以开方一会不可以,这条SQL当时总共执行了230次,当时的CPU情况也是忽高忽低,伴随这条SQL语句的执行情况,从而最终证明CPU的飙升是由于这条慢SQL。当线上业务逻辑复杂的时候,你很难第一时间知道到底是由于那条SQL引起的,这个就需要对业务非常熟悉,对SQL很熟悉,否则就会白白浪费大量的排查时间。

最后的排查结果:

在头天晚上的时候添加了一条索引rx_create_time,当时没事,但是第二天却出了事故。

加索引前后走的索引不同,一个是走的rx_status(处方审核状态)单列索引,一个是走的rx_create_time(处方提交事件)单列索引,这个就要回到业务,因为处方状态是个枚举,且枚举范围不到10个,也就说线上29,000,000的数据量也就是被分成了不到10份,rx_status=5的值是其中一份,因而通过这个索引就可以命中很多行,这是业务规则,再套用MySQL的特性,主要是以下几条:

1、没加新索引rx_create_time的时候,由于order by后边没有索引,就看where条件中是否有合适的索引,查询选择器选定rx_status这个单列索引,而rx_status=5这个条件下限制的数据行在索引中是连续,即使需要的rx_id不在索引中,再回主键聚簇索引也来得及,由于order by后边没有索引,所以走磁盘级别的排序filesort,高峰积压的时候处方就1万到2万,跑到了100ms,白天低谷的时候几百单也就20ms。

2、新加索引之后,就分两种情况:

2.1、加索引是在晚上,当前命中的行数比较少,由于当天晚上的时候待审核的处方确实很少,也就是rx_status=5的确实很少,查询优化器感觉反正没多少行,排序不重要,因而就还是选择rx_status索引。

2.2、第二天白天,待审核的处方数量很多了(rx_status=5的数据量多了),当时可以命中几万数据,如果当前命中的行数比较多,查询优化器就开始算成本,感觉排序的成本会更高,那就优先保排序吧,所以就选择rx_create_time这个字段,但是这个索引树上没有别的索引字段的信息,没办法,几乎每条数据都要回表,进而引发了灾难。

8、 推荐用书

这本书以一种诙谐幽默的风格写了MySQL的一些运行机制,非常适合阅读,理解成本大幅降低。

http://item.jd.com/13009316.html

http://item.jd.com/10066181997303.html

9、一些感悟

关于数据库的性能优化其实是一个很复杂的大课题,很难通过一篇帖子讲的很全面和深刻,这也就是为什么我的标题是‘浅析’,程序员的成长一定是要付出代价和成本,因为只有真的在一线切身体会到当时的紧张和压力,对于一件事情才能印象深刻,但反之也不能太过于强调代价,如果可以通过一些别人的分享就可以规避一些自己业务的问题和错误的代价也是好的。

本文转载于网络 如有侵权请联系删除

相关文章

  • Swift 自定义Subscript

    大家好,又见面了,我是全栈君Swift可以方便给自定义类加下标,其中参数和返回值可以在类里定义为任意类型:subscript(parameters)->ReturnType{ get{ //returnsomeValue } set(newValue){ //setSomeValue() } }/*何问起hovertree.com*/复制下标通常是访问某些方法的快捷方式,就算对NSArray操作的时候一样。和计算属性一样,下标也能以只读或只写的方式出现,如只读下标:subscript(parameters)->ReturnType{ returnsomeValue }/*何问起hovertree.com*/复制如果一个类中支持多种下标,而且参数类型也是一样的,可以在访问该下标的时候显式地申明类型:letplayer:Type=Class[(3,4)] /*何问起hovertree.com*/复制发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/120388.html原文链接:https://javaforall.cn

  • 关于中文分词

    大家好,又见面了,我是全栈君,祝每个程序员都可以多学几门语言。眼下全量索引17G,不到1300万document花费大约25分钟的时间(Lucene4.0),吞吐量远远低于lucenenightlybuild宣称的170G/h的量。换用StandardAnalyzer,有34%的提高,比較下使用的KAnalyzer,mmseg4j1.9.2-snapshot,standardanalyzer,性能分别在1.7M/s,10M/s,20M/s这样量级。所以觉得假设分词性能有明显提高,索引速度应该会有加快。分析了下眼下使用的KAnalyzer,它同一时候运行正向最大匹配和反向最大匹配,取概率最大那个(1-gram累计词频),假设有歧义/交集的三元组,用概率算第三种分词方式,假设最高,当然选用第三种分词方式。感觉起来效率不太高,由于有三次匹配,我会尝试例如以下动作:1)分别測试仅仅使用最大正向和最大反向的性能,有个直观感觉,再建索引看看性能;2)mmseg相同是启示式的,但仅仅做一次匹配,孰优孰劣,还要看准确率,召回率,必须通过的測试是否都通过,这一套标准须要建立起来3)算法是一方面,词典质量

  • 某小说App返回数据 解密分析

    一、目标李老板:奋飞呀,最近被隔离在小区里,没啥可干的呀。奋飞:看小说呀,量大管饱。我们今天的目标就是某小说Appv2021_09_53二、步骤搜索url字符串App请求小说内容的时候没有加签名,但是返回的数据是加密的。main.png那么我们先去jadx搜索一下这个url(novel-content),看看有没有发现。结果是没有收获。那么很有可能这个url不是在apk中写死的,而是某个请求返回的。Charles可以搜索数据包,我们从返回包里面找到了这个url。main2.png那就好办了,看看是哪块代码去解析了这个content_url,我们在jadx中搜索"content_url"这次倒是有收获,但是看不出来这个变量再哪里用了。插播一个屏蔽登录只能再想想别的办法了,办法还没想出来,又遇到了新的问题。第二次启动app的时候,就不让我看书了。一定要我登录,一怒之下登录了,居然还不让我看。还要买VIP。这下忍不了了,我不过是想写个分析教程,何必这么为难我。先从提示入手,搜索"登录"来到这里login.png理论上说干掉这两个函数应该就可以了,写代码

  • windows10 ---- 修改网络 IP 的物理地址

    1.ipconfig/all查询当前IP物理地址打开网络与共享中心控制面板====》网络和Internet====》网络和共享中心====》更改适配器配置 选择当前连接网络选中当前连接的网络====》右键====》属性 配置修改网络地址的值高级===》网络地址===》值【56QW84RE02RF】===》确定 注意:值的位数保持12,数字字母自定义随便修改! 修改后查询IP的物理地址注意解决网络慢修改的ip物理地址,第一次修改物理地址虽然改变,但是网络速度变化不大,第二次修改就明显很快!此方法解决了本人的问题,如果没有解决你的问题,请再搜索其他文章!

  • 48. 旋转图像

    给定一个n×n的二维矩阵matrix表示一个图像。请你将图像顺时针旋转90度。 你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像 classSolution{ publicvoidrotate(int[][]matrix){ int[][]matrix_new=newint[matrix.length][matrix[0].length]; //原来的(i,j)元素变为(j,mat[0].length-i-1); for(inti=0;i<matrix.length;i++){ for(intj=0;j<matrix[0].length;j++){ matrix_new[j][matrix[0].length-i-1]=matrix[i][j]; } } //重新放回原军阵里面 for(inti=0;i<matrix.length;i++){ for(intj=0;j<matrix[0].length;j++){ matrix[i][j]=matrix_new[i][j]; } } } }复制

  • 这次,十分钟把宏任务和微任务讲清楚

    首页专栏javascript文章详情10这次,十分钟把宏任务和微任务讲清楚Peter谭老师发布于今天01:00为什么写这个文章这是一道大厂、小厂面试官都喜欢问的题目很多面试官和面试者也不知道什么是标准答案网上各种文章层次不齐..误导过不少人,包括我觉得还是今天花十分钟讲清楚他吧正式开始先上代码functionapp(){ setTimeout(()=>{ console.log("1-1"); Promise.resolve().then(()=>{ console.log("2-1"); }); }); console.log("1-2"); Promise.resolve().then(()=>{ console.log("1-3"); setTimeout(()=>{ console.log("3-1"); }); }); } app();复制输出结果:1-2 1-3 1-1 2-1 3-1复制开始分析面试官特别喜欢问:你讲讲什么是微任务和宏任务大部分面试官

  • Java 水题系列(1)数字金字塔

    1.数字金字塔思路:水题,模拟即可,小学生运算,求出有多少个空格就好,第一个循环控制行数,然后里面套两个循环写左边递减的数字和右边递减的数字/** *@Title:a.java *@Description:TODO *@author菱形继承 *@date2020-03-3103:12:45 */ /** *@ClassName:a *@Description:TODO *@author菱形继承 *@date2020-03-3103:12:45 */ importjava.util.Scanner; publicclassa{ publicstaticvoidmain(Stringargs[]) { Scannersc=newScanner(System.in); intn=sc.nextInt(); for(inti=1;i<=n;i++)//n在最外层控制行数 { for(intj=1;j<=n-i;j++) System.out.print(""); for(intk=i;k>=1;k--) S

  • Putty个性化配置

    终端工具用一圈,还是Putty简单好用。就是Putty难看的外观、不清晰的字体劝退了许多人,今天就简单介绍一种快速美化putty的方法。Putty的配置文件通过注册表来记录,因此通过修改注册表来修改其配置。将下列内容复制到一个name.reg文件中。WindowsRegistryEditorVersion5.00 [HKEY_CURRENT_USER\Software\SimonTatham\PuTTY\Sessions\InsideUbuntuServer] "Present"=dword:00000001 "HostName"="192.168.6.236" "LogFileName"="putty.log" "LogType"=dword:00000000 "LogFileClash"=dword:ffffffff "LogFlush"=dword:00000001 "SSHLogOmitPasswords&q

  • [MongoDB] 使用PHP在MongoDB中搜索的实现

    条件操作符用于比较两个表达式并从mongoDB集合中获取数据。 MongoDB中条件操作符有: (>)大于-$gt (<)小于-$lt (>=)大于等于-$gte (<=)小于等于-$lte MongoDB使用$regex操作符来设置匹配字符串的正则表达式,使用PCRE(PerlCompatibleRegularExpression)作为正则表达式语言。 MongoDBOR条件语句使用了关键字$or下面是具体一个PHP例子中的$filter数组:array(3){ ["$or"]=> array(2){ [0]=> array(1){ ["modelID"]=> string(12)"基础新闻" } [1]=> array(1){ ["name"]=> string(12)"基础新闻" } } ["createTime"]=> array(2){ ["$gte"]=> string(

  • ThunderNet | Two-stage形式的目标检测也可很快而且精度很高

    一导读在移动平台上进行实时通用目标检测是一项至关重要但具有挑战性的计算机视觉任务。然而,以往基于cnn的检测器面临着巨大的计算成本,这阻碍了它们在计算受限的情况下进行实时推断。今天,我们说的这个研究了two-stage检测器在实时通用检测中的有效性,提出了一种名为ThunderNet的轻量级的two-stage检测器。在主干部分,分析了以往轻量级主干网的不足,提出了一种面向目标检测的轻量级主干网络。在检测部分,开发了一种非常有效的RPN和detectionhead设计。为了产生更多的判别特征表示,设计了两个有效的体系结构块:上下文增强模块和空间注意力模块。ContextEnhancementModule(CEM)SpatialAttentionModule(SAM)最后,还研究了输入分辨率、主干网络和detectionhead之间的平衡。与轻量级one-stage检测器相比,ThunderNet在Pascal、VOC和COCO基准上仅占计算量的40%,实现了更好的性能。没有bells和whistles,新模型在基于ARM设备上运行为24.1fps。这是第一个在ARM平台上报告的实时检测

  • 安装python常用软件包

    1.更改pip源至国内镜像可用源: 豆瓣:https://pypi.douban.com/simple/ 清华:https://pypi.tuna.tsinghua.edu.cn/simple临时使用:pipinstall-ihttps://pypi.tuna.tsinghua.edu.cn/simplenumpy 永久更改: 创建文件,~/.pip/pip.conf,添加内容如下:[global] index-url=https://pypi.tuna.tsinghua.edu.cn/simple复制2.安装numpy、scipy、theanopipinstallnumpyscipytheano 问题: OSError:[Errno13]Permissiondenied:'/usr/local/lib/python2.7/dist-packages/scipy-1.0.0.dist-info'解决: 把权限改成当前用户(currentuser)可写的模式,sudochown-R'用户名'/usr/local/lib/python2.7 问题:

  • Altdns:运用置换扫描技术的子域发现工具

    Altdns是一款运用置换扫描技术的子域发现工具,它可以帮助我们查找与某些排列或替换匹配的子域。AltDNS接受可能存在于域下的子域中的单词(例如测试,开发,分期),以及获取你知道的子域列表。使用者只需提供两个输入列表,altdns就可以为我们生成输出大量可能存在的潜在子域并保存。这些保存好的子域列表,用作DNS爆破字典是个不错的选择。或者,你也可以使用-r命令,将生成的这些子域(多线程)直接解析后输出保存到文件当中。Altdns最好是配合大型的数据集工作,初始数据集最好有200或以上个子域,这样能帮助我们发现生成更多有效的子域。安装使用-subdomains.txt文件包含了目标的已知子域 -data_output文件将包含大量的更改和置换的子域列表 -words.txt是你想要置换子域的单词列表(即admin,staging,dev,qa)-单词以行分隔 -r命令解析每个生成的已排列的子域 -s命令用于指定altdns在哪保存已解析的排列子域结果。results_output.txt将包含被发现有效的且具有DNS记录的排列后子域的最终列表。 -t命令用于指定解析器同时使用的线程数

  • P1829 [国家集训队]Crash的数字表格

     P1829[国家集训队]Crash的数字表格  原题传送门  前置芝士 莫比乌斯反演 乘法逆元 数论分块  正文  //补充:以下式子中的除法均为整除 由题目可以得知,这道题让我们所求的数,用一个式子来表达即为:\(\boxed{ANS=\sum_{i=1}^n\sum_{j=1}^mLCM(i,j)}\) 而根据莫比乌斯反演的内容,我们可以对右边的式子进行进一步的推导: \[\begin{align} \sum_{i=1}^n\sum_{j=1}^mLCM(i,j)&=\sum_{i=1}^n\sum_{j=1}^m{ij\overgcd(i,j)}\\ &=\sum_{t=1}^nt\sum_{i=1}^n\sum_{j=1}^m{ij\over{t^2}}[GCD({i\overt},{j\overt})=1]\\ &=\sum_{t=1}^nt\sum_{i=1}^{n\overt}\sum_{j=1}^{m\overt}ij[GCD(i,j)=1]\\ &=\sum_{t=1}^ntf({n\

  • JetBrains Rider 破解 (ideaIU等等开发工具都通用)2018-02-27

    JetBrains全家桶破解思路(以DataGrip为例)https://www.cnblogs.com/dotnetcrazy/p/9711763.html     贴一下Rider下载地址:(下载不了可以用百度云离线下载) Win: https://download.jetbrains.com/resharper/JetBrains.Rider-2017.3.1.exe https://download.jetbrains.8686c.com/rider/JetBrains.Rider-2018.1.exe Linux: https://download.jetbrains.com/resharper/JetBrains.Rider-2017.3.1.tar.gz https://download.jetbrains.8686c.com/rider/JetBrains.Rider-2018.1.tar.gz Mac: https://download.jetbrains.com/resharper/JetBrains.Rider-2017.3.1.dmg h

  • 耳机jack构造及在应用时可能出现的问题

      目前市场上耳机分为4环耳机(图1所示,iphone型)和3环耳机(图2所示)。4环耳机称为headset,3环耳机称为headphone,两者之间的区别就是4环耳机比3环耳机多个micphone。而Jack其实就是PC、PAD&Phone等设备上的耳机插口。                                                              &nb

  • 面试准备——(三)Selenium(1)基础问题及自动化测试

    转载:https://www.cnblogs.com/lesleysbw/p/6413880.html 面试准备——(三)Selenium(1)基础问题及自动化测试   滴滴面试: 1.自己负责哪部分功能? 农餐对接系统分为了两大子系统,一个是个人订餐系统,二是餐馆、个人与农产品供应商进行农产品交易系统。我主要负责组织测试人员对该系统进行测试。 我们测试分为两个阶段: 一、功能测试阶段。主要负责编写测试计划、测试用例、部署禅道BUG管理系统,进行功能测试。 首先,我们将系统分为了订餐平台、采购平台、登录注册、消费者/餐馆/供应商后台等七个模块。 其次,使用等价类划分和边界值分析法相结合,针对每个模块设计测试用例。 二、UI层自动化测试。使用PO设计模式,工具是Selenium+Unittest+Jenkins。 2.1目的 这个阶段,是在我们项目需求已经明确,版本已经稳定的情况下开始的,主要考虑了几个方面: 1.UI层在多平台、多浏览器下运行结果存在不同。也就是需要我们在不同平台、浏览器下运行相同的测试案例,大量的重复劳作力 2.其次,我们项目因为前期设计不够严谨、版本部

  • 如何理解e.preventDefault();e.stopPropagation();?

    如何理解e.preventDefault();e.stopPropagation();? e.preventDefault();//阻止默认行为 e.stopPropagation();//阻止冒泡行为 在jQuery事件中returnfalse等效于同时调用e.preventDefault()和e.stopPropagation(),returnfalse除了阻止默认行为之外,还会阻止事件冒泡 if(ret===false){ event.preventDefault(); event.stopPropagation(); } 复制 文章来源:刘俊涛的博客欢迎关注公众号、留言、评论,一起学习。 若有帮助到您,欢迎捐赠支持,您的支持是对我坚持最好的肯定(_) 你要保守你心,胜过保守一切。 本文来自博客园,作者:刘俊涛的博客,转载请注明原文链接:https://www.cnblogs.com/lovebing/p/16837163.html

  • Codeforces Round #460 (Div. 2)

    A 签到 B 题意 定义:一个数(没有前缀0)的各个位数之和为10位“perfec”数,问第k个“perfect”数位多少(1<=k<=1e5) 分析 一开始找错了,以为会超过1e9,通过理性的分析不难发现,最大不超过1e9,强行打个表即可 C 签到 D 题意 n个点m条边的有向图,每个点有一个数字(可以重复,0~25),定义一条路径的权值为该路径出现数字最多的数字的次数,若有环输出-1,否则输出最大值(1 ≤ n, m ≤ 300 000) 分析 思路:首先直接dfs肯定不行,最坏情况n^2,      问题就在于:如何记忆的记录已经搜索的路的每个数字的次数      解决:dp思想,每个点记录下到改点的所有数字的次数即可 正解:拓扑排序+dp 拓扑排序的时候dp即可 定义:dp[i][j]:第i个点数字j的最大值 转移:直接从上一个节点到当前节点转移即可 时间复杂度(26*m) #include<bits/stdc++.h> #definelllon

  • Oracle 导出的表不全,以及数据库版本不同导入报错

    公司有两个环境下的数据库,版本不同,一个是11gr2,另一个是10gr2 首先在11gr2下用exp导出数据库备份文件,发现部分表缺失。 原来这部分表是空的,11G中新特性,当表无数据时,不分配segment,以节省空间。而使用exp命令时,无Segment的表不会被导出。 解决方案: http://wenku.baidu.com/view/7beb56f57c1cfad6195fa702.html   好不容易全部导出来后,在10gr2环境下使用imp命令导入时报错: IMP-00010:notavalidexportfile,headerfailedverification 解决办法: 头部验证失败是由于版本号不同所致,经试验可以通过如下方法进行修改:用notepad++工具打开dmp文件,可以看到头部信息--TEXPORT:V11.01.00,即为源数据库的版本号,将其修改为目的数据库的版本号,如本机的版本号为10.02.01,再次进行导入操作尝试。导入不成功也有可能是因为数据库用户不对造成的。  

  • MinIO 分布式集群搭建

    MinIO分布式集群搭建 分布式Minio可以让你将多块硬盘(甚至在不同的机器上)组成一个对象存储服务。由于硬盘分布在不同的节点上,分布式Minio避免了单点故障。 Minio分布式模式可以搭建一个高可用的对象存储服务,你可以使用这些存储设备,而不用考虑其真实物理位置。 (1)数据保护 分布式Minio采用纠删码(erasurecode)来防范多个节点宕机和位衰减(bitrot)。 分布式Minio至少需要4个节点,使用分布式Minio就自动引入了纠删码功能。 纠删码是一种恢复丢失和损坏数据的数学算法,Minio采用Reed-Solomoncode将对象拆分成N/2数据和N/2奇偶校验块。这就意味着如果是12块盘,一个对象会被分成6个数据块、6个奇偶校验块,你可以丢失任意6块盘(不管其是存放的数据块还是奇偶校验块),你仍可以从剩下的盘中的数据进行恢复。 纠删码的工作原理和RAID或者复制不同,像RAID6可以在损失两块盘的情况下不丢数据,而Minio纠删码可以在丢失一半的盘的情况下,仍可以保证数据安全。而且Minio纠删码是作用在对象级别,可以一次恢复一个对象,而RAID是作用在卷级别

  • hexo + gitee部署博客

    前提:创建码云账号、安装了node.js与git   1.安装hexo框架 npminstall-ghexo-c2.hexoinit文件名(或者以创建相应文件在该文件下cmd中hexoinit)3.hexo-g本地生成静态文件hexoserver运行4.上传到gitee搭建远程可访问博客4.1创库创建后:复制URL,到hexo的配置文件_config.yml复制 deploy: type:git #type为git repo:https://gitee.com/somata/somata #仓库的URL复制 npminstallhexo-deployer-git--save #安装git插件 gitconfig--globaluser.email*********@qq.com #设置gitee邮箱(gitee的注册邮箱) gitconfig--globaluser.name'****' #设置用户名(git的注册昵称) hexodeploy-g(hexod-g)#上传到gitee #在上传时,需要再次输入gitee的注册邮箱作为username,账户密

相关推荐

推荐阅读