2019年10月

名称报名日期考试日期报考费用备注(其它条件)
软考上半年:03-13~03-31
下半年:08-13~08-28
5 月份第三个周六
11 月份第三个周六
高级资格:200 元
中级资格:170 元
初级资格:160 元(信息处理技术员 220 元)
因报名地域和时间的不同,报名费用会略有差别,以当地当时为准。
参考链接
PMP-每年的3月、6月、9月和12月
一般会选择一个周六的上午来考试
初考(非 PMI 会员) 3300
初考(PMI 会员) 2400
重考(非 PMI 会员) 2190
重考(PMI 会员) 1875
参考链接
微软-周一至周五工作日100 美元不等参考链接
IBM-在线-参考链接
Lotus-
Sun-
Oracle-
Cisco-
Adobe-
Hp-
Linux-
CIW-
Java-
Rea Hat-
华为认证预约制-参考链接

被授权人权利

被授权人有权利使用、复制、修改、合并、出版发行、散布、再授权及贩售软件及软件的副本。

被授权人可根据程序的需要修改授权条款为适当的内容。

被授权人义务

在软件和软件的所有副本中都必须包含版权声明和许可声明。

其他重要特性

此授权条款并非属copyleft的自由软件授权条款,允许在自由/开放源码软件或非自由软件(proprietary software)所使用。
MIT的内容可依照程序著作权者的需求更改内容。此亦为MIT与BSD(The BSD license, 3-clause BSD license)本质上不同处。

MIT条款可与其他授权条款并存。另外,MIT条款也是自由软件基金会(FSF)所认可的自由软件授权条款,与GPL兼容。

来源 | 阿里技术官方公众号(ali_tech)云服务 OpenAPI 的7大挑战,架构师如何应对?

云服务 OpenAPI 的7大挑战,架构师如何应对?_0.webp

阿里妹导读:API 是模块或者子系统之间交互的接口定义。好的系统架构离不开好的 API 设计,而一个设计不够完善的 API 则注定会导致系统的后续发展和维护非常困难。比较好的API设计样板可以参考 Github 和 K8s,它们都是典型的 RESTful 接口。云服务对外开放的窗口就是 OpenAPI,今天要讨论的话题是“云服务场景下 OpenAPI 设计的挑战”。

为什么要有 API 规范

之所以强调“云服务”的原因在于,小规模独立 API 的设计与大规模批量生产 API 面临的问题是不一样的。同样,只专注于自身产品 API 的可用性与从更高的层次去看云服务整体 API 体系的健壮性,要建设的体系也是不一样的。

例如,做一个 WEB 页面使用的 API,只需要考虑性能、稳定性、鉴权就好,因为页面与 API 是一体的,可以一起发布和回滚,只要功能正常,即便 API 设计有缺陷,用户也可以接受。而云服务要开放 API 考虑问题就多了:

  • 首先,云服务开放的是基础设施和服务接口,一般是系统级的对接,API 一旦开放想要变更就非常困难;
  • 其次,云服务并非单独运行,不同的产品实际场景中是互相组合的,需考虑产品间的一致性和互通便利性;
  • 云服务 API 数量庞大,为了更方便使用,配套的 API 查找、编排、自动化生成SDK等需求也比普通服务强烈;
  • 云服务的稳定性非常重要,核心产品的稳定性就是客户的生命线,要求非常高。

所以云服务由于产品线众多,需要统一的 API 规范来保证云产品间 API 体验一致,在底层平台层面互相兼容,便于上层应用平台化,同时要兼顾到围绕公有云服务的第三方生态、开源生态、企业生态。

在具体规范层面,业界也在不断尝试,比较知名的是 OpenAPI Specfication 和 Google API Design Guide。前者针对 RESTful API 设计在细节层面给出了非常具体的规定,已经成为 RESTful API 设计领域的事实标准,而后者则主要从云厂商的角度提出许多最佳实践性质的规范与建议,这些原则不仅仅适用于 RESTful API ,也适合其他类型 API 设计。对 API 设计感兴趣的开发者,可以详细研究一下资料。

2018年Openapi Specification发布了3.0版本
图片来源:https://swagger.io/

因此,对于云服务商来说,在关键环节制定明确的 API 规范有助于云服务对内提高产品间互通的效率,对外提供一致的使用体验,有助于云服务更好地被集成。那么要做好云服务的横向规范会碰到哪些困难呢?本文就从实践中总结了 7 大挑战。

挑战1:选择 API 设计模式

当你在考虑单个产品的 API 表现形式时,首先会选择一种具体的 API 风格,常见的有 RPC(Remote Procedure Call) 和 ROA(the Rest-Oriented Architecture) 两种模式,然后针对复杂的数据结构你会考虑使用什么样的序列化协议,常见的包括 Json/Xml/WSDL/Hessian 等,用于封装传输数据。但涉及到不同的产品时,在具体选型时考虑的问题可能就不太一样了。

gRPC示意图
图片来源:https://www.grpc.io/docs/guides/

虽然 RESTful 设计风格曝光率很高,但并不是所有云服务商都选择了完全遵循 RESTful,例如 AWS 和阿里云 RPC 风格反而占了大多数,Google 和 Azure 则 RESTful居多。

Restful API 的优势是 HTTP 具备更好的易用性,让异构系统更容易集成,且开发执行效率比较高,面向资源要求也比较高。而 RPC API 可以使用更广泛的框架和方案,技术层面更底层也更为灵活,设计起来相对简单,掌握起来有一定门槛,架构上更加复杂。

RESTful 与 RPC 模式对比

不同的团队根据实际情况和业务形态可能选择不同的方案,那云服务作为一个整体应该强制统一好还是随意选择好?如果强制统一风格,有些适合 RESTful风格的服务非要使用 RPC 的话,看起来就会比较丑陋,如果只是一个过程化的服务调用,往 RESTful 资源化设计方向去靠会比较困难。但如果不强制使用统一风格,会造成针对 API 的体系化支持会更加复杂,例如为兼容两种风格 SDK 的自动化支持需要两套代码。

通常 RESTful 风格对 API 设计者的要求是比较高的,主要的难点在于面向资源设计要求开发者事先做好规划,将后端数据模型与 API 服务模型相匹配。所以 RESTful API 的开发者应该是熟知系统整体实体关系模型的,很难想象一个不懂后台业务的新手能设计出合理的 API 来。那么是不是 RPC 风格 API 就不需要面向资源设计了呢?从实践中来看,并不是!RPC 风格的 API 也需要资源模型来支持,在下一节中会重点分析。

所以,对于云服务商来说,选择 API 风格时要考虑几个问题:

  • 选择支持哪种风格,才能更好地体现业务特性,让客户操作起来更加方便;
  • 设计 API 时能否面向资源设计,相应的工程人员是否具备做这种设计的能力;
  • 针对这种风格工具链的支持是否到位,投入产出比如何;
  • 业界流行的趋势如何,是否需要考虑与其他系统体系的互操作。

选定了具体设计模式后,就要努力做到统一,避免多种模式混杂带来管理成本的上升。 如果确实有必要两种方式都支持(例如阿里云就同时支持 RPC 和 ROA),就需要在技术上做好充分的准备。

挑战2:面向资源设计 API

用户使用 API 来访问云服务,本质上是想通过对某种云资源执行特定的操作来完成一个业务动作。Restful API 需要面向资源设计众所周知,那为什么RPC接口在云服务场景下也需要有资源模型呢?

RPC 形式的 API 组织形态是领域和行为(对象和方法),随着时间的推移, API 越来越多最终形成一个庞大的集合。以阿里云为例,对外开放的 OpenAPI 数量已经达到 10000 多个,涵盖了接近 200 个不同的产品。因为开发者必须单独学习每个 API ,耗时又容易出错,如果没有一个脉络的理解起来比较困难。 如果有一套标准的资源模型, API 就可以按照资源模型的维度分类组织,用户使用起来也会有迹可循 ,体验上会更好,否则面对如此多的 API 一点点学习无疑是个痛苦的过程。

另外,云服务并非单个服务的简单排列,它是多个体系的横向整合,总体对外呈现出有机连接。随着云计算的发展,企业客户对对云服务的要求不断提高。最典型的就是当企业客户大规模开始上云后,对虚拟化的云产品提出了各种管理需求,例如鉴权、编排、弹性伸缩等。

企业客户对云服务的管理需求

以最常用的鉴权功能为例,客户创建了一组云服务器来跑业务,运维人员需要有重启服务器的权限,其他角色人员则不需要此类权限,针对RestartServer这么一个 API 就需要进行权限控制了。权限在云平台中一般是中心式管理的,单独的云产品不需要分别管理。如果统一处理鉴权,就需要知道当前 API 正在操作什么资源,与此相关的资源有哪些(例如与服务器有关的资源包括磁盘、网卡、网络等关联资源),然后针对所有相关资源逐一鉴权才能确认 API 操作是否可行。

上面提到的资源有两个关键点,一是要有统一的资源模型,便于云产品对特定的 API 进行鉴权,二是要明确资源关系,当出现资源依赖的时候,需要关联鉴权。在 Google 的 API Guide 中就明确提到需要资源关系,可以看出资源关系不仅仅是用来做 API 设计建模的,它对于平台功能的实现也有至关重要的作用。不了解资源关系,有可能把多个资源封装到一个 API 中,使用和变更都很痛苦,即便后期发现了问题再补救拆开,由于很多用户已经在使用了,要付出的开发成本和沟通成本也是极大的,甚至成为不可能。所以 清晰的资源模型有利于梳理清楚 API 体系。

定义清晰的实体关系图有助于设计出更为完整的 API

而且,明确的资源模型对于构建云上运维管理基础设施至关重要,例如可以通过对资源打 Tag 来对资源进行分类管理(参考阿里云资源 Tag ),分组授权(参考阿里云资源组),资源审计(参考阿里云 CloudConfig ),类似开源软件 Terraform 这样的编排工具,由于有资源模型会更容易接入和使用。

所以,统一的资源模型对云服务的帮助是巨大的:

  • 它可以使 API 具有更清晰的结构,帮助用户理解;
  • 它可以帮助对比 API 与后台实体关系模型,更容易提供更完整的 API 服务;
  • 它可以使产品协作更加顺畅,对资源的操作也更加规范化;
  • 它可以使云服务底层平台实现起来更统一、更方便;
  • 它可以使围绕 API 的生态集成起来更加简单、高效。

既然有这么多好处,那么众多的云产品在实际设计 API 的时候能否坚持以资源为中心,充分考虑到上下游的需求就变成一个很大的挑战了。

挑战3: API 设计风格

确定了设计模式和资源模型后,是时候进入到 API 设计细节了。诸如 API 名称、参数名、属性名称、数据格式、错误码之类的信息,看起来根本不是问题。单个产品问题还不大,只要保证内部风格一致即可,如果考虑到云服务多产品对外的整体体验,就有必要考虑以下问题:

  • 在 API 命名的时候,遵循什么样的范式来确保大体风格相似?动词、名词、介词如何组合才能保持 API 风格看起来比较统一,降低理解成本?
  • 对于类似的操作,有没有使用规范?有哪些公共的标准词汇使得同类型的操作可以比较容易理解,避免使用晦涩奇怪的词汇(例如读操作,Read/Query/Describe/List/Get 中都在什么场合使用什么动词)?
  • 被广泛使用的参数如何尽可能保持一致,避免不同产品的表达混乱的情况(例如分页参数用 PageNumber 还是 PageNum)?
  • 对于常用的场景,例如幂等、分页、异步 API 的设计有没有统一的规范,避免使用体验不一致?
  • 错误码应该怎么设计?公共错误码怎么统一,业务错误码怎么表达?

上述问题都是实际研发过程中要注意的,要全部罗列的话远不止这些。 API 的用词描述是云服务展现给外部用户的第一印象,绝非随意写就。对人员有一定规模,内部有多条产品线的组织来说,如何协调组织的各个部分对外具有统一的体验是个很大挑战。

回顾下HTTP协议,最广为认知的是对HTTP Mehod的约定,使用9个单词就完成了对基本动作的规范,为开发者提供了清晰的思维模型:

Http Method 类型
图片来源:https://tools.ietf.org/html/rfc7231

同样,在 HTTP Header 里面也对浏览器信息、语言、网络连接属性等做了详细的规定,这样开发者在使用 HTTP 服务的时候都有一个大致的约定,在关键信息上面不会有偏差,保障了异构系统的接口一致性。

因此云服务在管理 API 时应该考虑一些具体的规范,对命名规则、标准词汇、最佳实践模式、错误码等信息都有明确的规定,同时用系统化、平台化的手段来管理 API ,确保不走偏。设计风格不是云服务 API 设计中致命的问题,但是它关乎云服务外表形象,不可不察。

挑战4:服务端容错处理

API 是后端服务的外部表达,是服务就有可能出现问题,无论这个问题是可预期的还是不可预期的。如果只考虑功能本身功能特性,而忽视对异常情况的设计,当问题出现的时候业务本身可能无法感知造成服务异常,更重要的是站在客户角度去看,不能有效获取错误原因是非常痛苦的,很多时候只能束手无策,降低云服务提供商的整体口碑,甚至损害营收。

假设有个创建资源的 API ,每调用一次都会创建新的资源,考虑以下情况:

  • 同样的请求多次提交,是否会重复创建资源?
  • 请求处理时间过长,客户端是长时间等待,还是先异步返回一个任务ID?
  • 如果需要等待,Timeout 最大值是多少?
  • 如果 Timeout 最大值达到,客户端的策略是重试还是放弃
  • 如果最终处理还是失败了,具体是哪个环节的问题?如何给出准确的错误信息?
  • 如果异步方式,异步处理完成后是主动查询还是另有通知?
  • 第三方工具和集成商到哪里去获取这些信息?能不能有标准化的处理?

实践中,如果不做好问题 a 的处理,可能会造成系统异常情况下大批资源被重复创建,有可能造成用户或云服务商资损;问题 b-e 没有处理好,可能会让用户陷入盲目等待或者盲目重试,使用体验和效率极差;而 f-g 关系到自动化处理工具如何做到效率最大化,也关系到被集成的效率。

一个异步重试的状态机

当出现异常的时候, API 一般是要靠错误码来告知用户有什么问题。HTTP 协议本身对错误码做出了详尽的规定,Restful 的 API 要尽可能地符合标准。除此之外,云服务有必要在此基础上进一步提供业务错误码和错误信息,来描述错误具体的细节。

当前云服务的错误码很多,看起来非常专业,但问题主要集中在以下几个方面:

1.错误类型过多: 错误码越多客户端处理起来越方便吗?看一下 HTTP 的错误码,只有 5 大类加几十个子类的错误码就涵盖了所有场景,而通常大家耳熟能详的无非是 200、400、404、500、502 等屈指可数的状态码。有的人考虑错误码越多,客户端可以 switch/case 一下针对每个错误码做不同的操作,这个就见仁见智了,一般的程序员可能不会写那么多的分支流程,必要性也不大。

2.错误信息表达不够充分: 相比于提供大量的错误码,错误信息的明确表达更为重要。如果错误信息不够详细,作为用户不了解细节无法掌控的云服务,几乎是无法明确发生了什么,要么提工单,要么只能被动等待,客户体验很差。

3.业务错误码与HTTP错误码含义不匹配: 例如参数错误应该返回 4xx 系列 Code,返回 5xx 系列就不够专业。即便是 RPC 风格的 API,也要大致符合 HTTP 规则,否则可能会给一些依赖 HTTP Code 的系统造成误导。网上有种思路觉得无论后台响应如何,HTTP Code 统统返回 200,在 Body 里面的错误信息体现异常信息,这种不利于对接口的监控,因为监控系统很难通过识别消息体来鉴别功能是否正常响应。

4.相同错误不同云产品表达不一致: 这会给客户端开发造成困扰,增加开发工作量,不利于自动化集成,用户体验比较差。

5.错误码应该是可枚举集合: 一个 API 能够产生的错误码类型应该是可预期的,即便是业务升级,也应该给客户提供明确的错误码列表,不能随心所欲。因为用户端需要明确知道可能会发生什么,而不是随时可能出现不可预知的错误类型。如果错误类型不确定,就意味着针对错误码分支处理基本是无效的。

要做好服务端容错上述问题,需要从云服务整体层面加强 API 的容错设计,做好错误码规范,加强对错误信息的管理,来提升用户体验。

挑战5:版本管理

API 都是不断迭代的,通常都需要版本管理。云服务 API 的版本管理尤其重要,主要是以下原因:

  • 云服务 API 直接面向用户,由于调用量大,变更影响的用户范围也更广,版本变更要非常谨慎;
  • 云服务有多种形态,主要是公有云、私有云、细分的行业云等,不同的云对同样功能 API 的要求可能不一样, API 更加多样化。既要保障不同版本功能正常,又要能快速部署维护不同版本,挑战很大;
  • 不兼容变更的推广极其困难,很难让用户在短时间内快速升级,维护多版本 API 成本很高;
  • 必须变更的情况,要确保调用方能够及时感知并且平滑切换的技术难度很大。

针对 API 各种场景的管理,需要一套成熟的 API 管理平台,照顾到各种场景的需求,也是一项不小的挑战。

挑战6: API 该如何开放

API 如何开放看起来是奇怪的问题,难道 API 做出来不就是开放给别人用的吗?做好就开放就开放啊?但在云服务场景下,情况会更复杂一点!

产品技术都是在不断迭代的,功能始终在增加,新的 API 层出不穷。从客户视角来看,他们对已开发完毕的 API 是否开放的需求是什么?假设一个云产品有 100 个功能特性,20 个只能保留在内部,官网上总共提供了 80 个特性,而公开 API 只开放了 50 个,这是用户期望的状态吗?理想状态应该是什么?

围绕云服务有一个庞大的生态,除了普通的开发者,还有许多第三方服务商、企业客户、开源工具。当我们考虑所有这些生态成员的需求时会发现:云服务自身拥有的功能集合与客户能使用的功能集合之间的差异比较能体现产品的开放程度。这里的差异强调的是云服务已经拥有的,不包括云服务自身没有的服务。客户能使用的功能与云服务能提供的功能之间的差距越大,说明云产品的开放程度越低,因为很多功能都作为保留节目被雪藏了,导致客户和第三方服务商无法享受与云厂商接近的服务,最终生态无法拓展。 理想状况是,云服务商自身能通过 API 使用的功能,客户都能通过 OpenAPI 使用,内外看到的是一致的。

但具体到某个 API 应不应该开放,实践中会做如下考虑:

  • API 刚刚上线尚未打磨充分,贸然开放可能会留下隐患,再想调整为时已晚,所以选择先不开放。
  • API 本身并非原子化,封装了若干业务场景,主要目的是优化性能或者服务特定的客户,并不需要开放给所有用户;而且当业务场景发生变化的时候,调整起来也比较困难,不适合开放出去。
  • 某些 API 不适合开放给全部用户,只能部分开放,例如特定行业专业的 API。
  • API 仅供特定场景或私有场景使用,需要外部能够访问,但是不能开放给用户。

针对这些问题,需要在 API 的管理机制上面下功夫,能够区分不同的场景,并做好元数据的管理。针对 API 是否开放要有明确的规范和度量机制,确保该开放的 API 都可以开放,确保内外客户看到的功能集合基本一致,才有利于云服务更好地被集成,在客户的业务中发挥更大的作用。

挑战7:API 体系如何打通

在云服务场景中,API 并非孤立存在:

首先,API 发布以后,用户要想顺利地使用 API,配套设施必不可少,SDK、文档、工具链的集成都需要考虑到,这里的重点是如何保障准确性、及时性和一致性。开发工程师一般都不太喜欢写文档,专业写文档的又可能不太懂技术,再考虑到国际化的问题,就十分有挑战了。SDK 方面,一个 API 要有多种语言的实现,每种语言还要保障其专业性、可用性,非常考验对开发人员编程语言掌握的深度和对 API 的理解,业界经常采用的自动化生成SDK的方式也会考验对多语言的兼容能力。工具链比如阿里云的 API Explorer、CloudShell 等产品也需要及时与 API 的最新状态保持同步。

其次,云服务由于产品线众多,如何让用户能够快速学习使用 API 和相关工具,需要在教程、案例、运行时环境等诸多方面加强建设。围绕云服务,已经发展出许多上层生态工具,例如 terraform/ansible/spinnaker 等开源软件,它们能够帮助云服务更好地使用起来,必须对它们提供支持,如何能够快速覆盖也对平台开发能力是个考验。

另外,API 本身的质量保障也是非常重要的。一般都要考虑性能、稳定性、安全等方面的保障体系,通过压测、监控、部署防护软件等方式来确保 API 在服务的时候不会掉链子。传统的套路在解决系统问题时非常有效,但具体到业务问题的时候就无能为力了。例如,一个创建服务器的 API 一般来说都是要求幂等的,怎么检测该 API 实际上有没有做到幂等呢?推而广之,其他业务流程的正确性又如何保障呢?等 API 开放了发现问题再修复就为时已晚,显然应该在上线前通过测试来发现这类问题。但是随着业务的发展,如何能保障这类问题可以有统一的解决方案,能够长期跟进及时发现风险避免损失呢?

阿里云 API 体系简易图

所谓量变引起质变,上述问题针对单个 API 的时候都好解决,但是当 API 规模达到成千上万的时候,就必须通过平台化、系统化的手段来解决了。例如, API 服务可靠性SLA指标如果要达到 4 个 9,需要制定明确的标准,并且有手段监控到所有 API 的运行结果,通过分析成功率来判断其是否达到预期水平,这对云服务本身的底层系统建设提出了较高的要求。

所以,以 API 为中心完善相关体系,保障用户体验的一致性、及时性、稳定性、易用性是非常有挑战的。

参考文献:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Messages
https://tools.ietf.org/html/rfc7231#section-4
https://www.cnblogs.com/sparkdev/p/10052310.html
https://www.grpc.io/docs/guides/
https://www.terraform.io/docs/index.html
http://www.grabsun.com/article/2015/1135807.html

end

24 个必须掌握的数据库面试问题!_1.jpg

一、为什么用自增列作为主键

1、如果我们定义了主键(PRIMARY KEY),那么InnoDB会选择主键作为聚集索引。

如果没有显式定义主键,则InnoDB会选择第一个不包含有NULL值的唯一索引作为主键索引。

如果也没有这样的唯一索引,则InnoDB会选择内置6字节长的ROWID作为隐含的聚集索引(ROWID随着行记录的写入而主键递增,这个ROWID不像ORACLE的ROWID那样可引用,是隐含的)。

2、数据记录本身被存于主索引(一颗B+Tree)的叶子节点上,这就要求同一个叶子节点内(大小为一个内存页或磁盘页)的各条数据记录按主键顺序存放

因此每当有一条新的记录插入时,MySQL会根据其主键将其插入适当的节点和位置,如果页面达到装载因子(InnoDB默认为15/16),则开辟一个新的页(节点)

3、如果表使用自增主键,那么每次插入新的记录,记录就会顺序添加到当前索引节点的后续位置,当一页写满,就会自动开辟一个新的页

4、如果使用非自增主键(如果身份证号或学号等),由于每次插入主键的值近似于随机,因此每次新纪录都要被插到现有索引页得中间某个位置

此时MySQL不得不为了将新记录插到合适位置而移动数据,甚至目标页面可能已经被回写到磁盘上而从缓存中清掉,此时又要从磁盘上读回来,这增加了很多开销

同时频繁的移动、分页操作造成了大量的碎片,得到了不够紧凑的索引结构,后续不得不通过OPTIMIZE TABLE来重建表并优化填充页面。

二、为什么使用数据索引能提高效率

  1. 数据索引的存储是有序的
  2. 在有序的情况下,通过索引查询一个数据是无需遍历索引记录的
  3. 极端情况下,数据索引的查询效率为二分法查询效率,趋近于 log2(N)

三、B+树索引和哈希索引的区别

B+树是一个平衡的多叉树,从根节点到每个叶子节点的高度差值不超过1,而且同层级的节点间有指针相互链接,是有序的,如下图:

24 个必须掌握的数据库面试问题!_2.jpg

哈希索引就是采用一定的哈希算法,把键值换算成新的哈希值,检索时不需要类似B+树那样从根节点到叶子节点逐级查找,只需一次哈希算法即可,是无序的,如下图所示:

24 个必须掌握的数据库面试问题!_3.jpg

四、哈希索引的优势:

等值查询,哈希索引具有绝对优势(前提是:没有大量重复键值,如果大量重复键值时,哈希索引的效率很低,因为存在所谓的哈希碰撞问题。)

五、哈希索引不适用的场景:

  1. 不支持范围查询
  2. 不支持索引完成排序
  3. 不支持联合索引的最左前缀匹配规则

通常,B+树索引结构适用于绝大多数场景,像下面这种场景用哈希索引才更有优势:

在HEAP表中,如果存储的数据重复度很低(也就是说基数很大),对该列数据以等值查询为主,没有范围查询、没有排序的时候,特别适合采用哈希索引,例如这种SQL:

仅等值查询

select id, name from table where name='李明'; 

而常用的 InnoDB 引擎中默认使用的是B+树索引,它会实时监控表上索引的使用情况。

如果认为建立哈希索引可以提高查询效率,则自动在内存中的“自适应哈希索引缓冲区”建立哈希索引(在InnoDB中默认开启自适应哈希索引)。

通过观察搜索模式,MySQL会利用index key的前缀建立哈希索引,如果一个表几乎大部分都在缓冲池中,那么建立一个哈希索引能够加快等值查询。

注意:在某些工作负载下,通过哈希索引查找带来的性能提升远大于额外的监控索引搜索情况和保持这个哈希表结构所带来的开销。

但某些时候,在负载高的情况下,自适应哈希索引中添加的read/write锁也会带来竞争,比如高并发的join操作。like操作和%的通配符操作也不适用于自适应哈希索引,可能要关闭自适应哈希索引。

六、B树和B+树的区别

1、B树,每个节点都存储key和data,所有节点组成这棵树,并且叶子节点指针为nul,叶子结点不包含任何关键字信息。

24 个必须掌握的数据库面试问题!_4.jpg

2、B+树,所有的叶子结点中包含了全部关键字的信息,及指向含有这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大的顺序链接

所有的非终端结点可以看成是索引部分,结点中仅含有其子树根结点中最大(或最小)关键字。(而B 树的非终节点也包含需要查找的有效信息)

24 个必须掌握的数据库面试问题!_5.jpg

七、为什么说B+比B树更适合实际应用中操作系统的文件索引和数据库索引?

1、B+的磁盘读写代价更低。

B+的内部结点并没有指向关键字具体信息的指针,因此其内部结点相对B树更小。

如果把所有同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就越多。相对来说IO读写次数也就降低了。

2、B+-tree的查询效率更加稳定。

由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。

八、MySQL联合索引

1、联合索引是两个或更多个列上的索引。

对于联合索引:Mysql从左到右的使用索引中的字段,一个查询可以只使用索引中的一部份,但只能是最左侧部分。

例如索引是key index (a,b,c). 可以支持a 、 a,b 、 a,b,c 3种组合进行查找,但不支持 b,c进行查找 .当最左侧字段是常量引用时,索引就十分有效。

2、利用索引中的附加列,您可以缩小搜索的范围,但使用一个具有两列的索引不同于使用两个单独的索引。

复合索引的结构与电话簿类似,人名由姓和名构成,电话簿首先按姓氏对进行排序,然后按名字对有相同姓氏的人进行排序。

如果您知道姓,电话簿将非常有用;如果您知道姓和名,电话簿则更为有用,但如果您只知道名不知道姓,电话簿将没有用处。

九、什么情况下应不建或少建索引

1、表记录太少

2、经常插入、删除、修改的表

3、数据重复且分布平均的表字段,假如一个表有10万行记录,有一个字段A只有T和F两种值,且每个值的分布概率大约为50%,那么对这种表A字段建索引一般不会提高数据库的查询速度。

4、经常和主字段一块查询但主字段索引值比较多的表字段

十、什么是表分区?

表分区,是指根据一定规则,将数据库中的一张表分解成多个更小的,容易管理的部分。从逻辑上看,只有一张表,但是底层却是由多个物理分区组成。

十一、表分区与分表的区别

分表:指的是通过一定规则,将一张表分解成多张不同的表。比如将用户订单记录根据时间成多个表。

分表与分区的区别在于:分区从逻辑上来讲只有一张表,而分表则是将一张表分解成多张表。

十二、表分区有什么好处?

1、存储更多数据。分区表的数据可以分布在不同的物理设备上,从而高效地利用多个硬件设备。和单个磁盘或者文件系统相比,可以存储更多数据

2、优化查询。在where语句中包含分区条件时,可以只扫描一个或多个分区表来提高查询效率;涉及sum和count语句时,也可以在多个分区上并行处理,最后汇总结果。

3、分区表更容易维护。例如:想批量删除大量数据可以清除整个分区。

4、避免某些特殊的瓶颈,例如InnoDB的单个索引的互斥访问,ext3问价你系统的inode锁竞争等。

十三、分区表的限制因素

  1. 一个表最多只能有1024个分区
  2. MySQL5.1中,分区表达式必须是整数,或者返回整数的表达式。在MySQL5.5中提供了非整数表达式分区的支持。
  3. 如果分区字段中有主键或者唯一索引的列,那么多有主键列和唯一索引列都必须包含进来。即:分区字段要么不包含主键或者索引列,要么包含全部主键和索引列。
  4. 分区表中无法使用外键约束
  5. MySQL的分区适用于一个表的所有数据和索引,不能只对表数据分区而不对索引分区,也不能只对索引分区而不对表分区,也不能只对表的一部分数据分区。

十四、如何判断当前MySQL是否支持分区?

命令:show variables like '%partition%' 运行结果:

have_partintioning 的值为YES,表示支持分区。

十五、MySQL支持的分区类型有哪些?

  1. RANGE分区:这种模式允许将数据划分不同范围。例如可以将一个表通过年份划分成若干个分区
  2. LIST分区:这种模式允许系统通过预定义的列表的值来对数据进行分割。按照List中的值分区,与RANGE的区别是,range分区的区间范围值是连续的。
  3. HASH分区 :这中模式允许通过对表的一个或多个列的Hash Key进行计算,最后通过这个Hash码不同数值对应的数据区域进行分区。例如可以建立一个对表主键进行分区的表。
  4. KEY分区 :上面Hash模式的一种延伸,这里的Hash Key是MySQL系统产生的。

十六、四种隔离级别

  1. Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
  2. Repeatable read (可重复读):可避免脏读、不可重复读的发生。
  3. Read committed (读已提交):可避免脏读的发生。
  4. Read uncommitted (读未提交):最低级别,任何情况都无法保证。

十七、关于MVVC

MySQL InnoDB存储引擎,实现的是基于多版本的并发控制协议——MVCC (Multi-Version Concurrency Control)

:与MVCC相对的,是基于锁的并发控制,Lock-Based Concurrency Control

MVCC最大的好处:读不加锁,读写不冲突。在读多写少的OLTP应用中,读写不冲突是非常重要的,极大的增加了系统的并发性能,现阶段几乎所有的RDBMS,都支持了MVCC。

  1. LBCC:Lock-Based Concurrency Control,基于锁的并发控制
  2. MVCC:Multi-Version Concurrency Control

    基于多版本的并发控制协议。纯粹基于锁的并发机制并发量低,MVCC是在基于锁的并发控制上的改进,主要是在读操作上提高了并发量。

十八、在MVCC并发控制中,读操作可以分成两类:

  1. 快照读 (snapshot read):读取的是记录的可见版本 (有可能是历史版本),不用加锁(共享读锁s锁也不加,所以不会阻塞其他事务的写)
  2. 当前读 (current read):读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录

十九、行级锁定的优点:

1、当在许多线程中访问不同的行时只存在少量锁定冲突。

2、回滚时只有少量的更改

3、可以长时间锁定单一的行。

二十、行级锁定的缺点:

  1. 比页级或表级锁定占用更多的内存。
  2. 当在表的大部分中使用时,比页级或表级锁定速度慢,因为你必须获取更多的锁。
  3. 如果你在大部分数据上经常进行GROUP BY操作或者必须经常扫描整个表,比其它锁定明显慢很多。
  4. 用高级别锁定,通过支持不同的类型锁定,你也可以很容易地调节应用程序,因为其锁成本小于行级锁定。

二十一、MySQL优化

  1. 开启查询缓存,优化查询
  2. explain你的select查询,这可以帮你分析你的查询语句或是表结构的性能瓶颈。EXPLAIN 的查询结果还会告诉你你的索引主键被如何利用的,你的数据表是如何被搜索和排序的
  3. 当只要一行数据时使用limit 1,MySQL数据库引擎会在找到一条数据后停止搜索,而不是继续往后查少下一条符合记录的数据
  4. 为搜索字段建索引
  5. 使用 ENUM 而不是 VARCHAR。如果你有一个字段,比如“性别”,“国家”,“民族”,“状态”或“部门”,你知道这些字段的取值是有限而且固定的,那么,你应该使用 ENUM 而不是VARCHAR
  6. Prepared StatementsPrepared Statements很像存储过程,是一种运行在后台的SQL语句集合,我们可以从使用 prepared statements 获得很多好处,无论是性能问题还是安全问题。

    Prepared Statements 可以检查一些你绑定好的变量,这样可以保护你的程序不会受到“SQL注入式”攻击

  7. 垂直分表
  8. 选择正确的存储引擎

二十二、key和index的区别

  1. key 是数据库的物理结构,它包含两层意义和作用,一是约束(偏重于约束和规范数据库的结构完整性),二是索引(辅助查询用的)。包括primary key, unique key, foreign key 等
  2. index是数据库的物理结构,它只是辅助查询的,它创建时会在另外的表空间(mysql中的innodb表空间)以一个类似目录的结构存储。索引要分类的话,分为前缀索引、全文本索引等;

二十三、Mysql 中 MyISAM 和 InnoDB 的区别有哪些?

区别:

  1. InnoDB支持事务,MyISAM不支持

    对于InnoDB每一条SQL语言都默认封装成事务,自动提交,这样会影响速度,所以最好把多条SQL语言放在begin和commit之间,组成一个事务;

  2. InnoDB支持外键,而MyISAM不支持。对一个包含外键的InnoDB表转为MYISAM会失败;
  3. InnoDB是聚集索引,数据文件是和索引绑在一起的,必须要有主键,通过主键索引效率很高。

    但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此主键不应该过大,因为主键太大,其他索引也都会很大。

    而MyISAM是非聚集索引,数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。

  4. InnoDB不保存表的具体行数,执行select count(*) from table时需要全表扫描。而MyISAM用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快;
  5. Innodb不支持全文索引,而MyISAM支持全文索引,查询效率上MyISAM要高;

如何选择:

  1. 是否要支持事务,如果要请选择innodb,如果不需要可以考虑MyISAM;
  2. 如果表中绝大多数都只是读查询,可以考虑MyISAM,如果既有读写也挺频繁,请使用InnoDB
  3. 系统奔溃后,MyISAM恢复起来更困难,能否接受;
  4. MySQL5.5版本开始Innodb已经成为Mysql的默认引擎(之前是MyISAM),说明其优势是有目共睹的,如果你不知道用什么,那就用InnoDB,至少不会差。

二十四、数据库表创建注意事项

1、字段名及字段配制合理性

  • 剔除关系不密切的字段;
  • 字段命名要有规则及相对应的含义(不要一部分英文,一部分拼音,还有类似a.b.c这样不明含义的字段);
  • 字段命名尽量不要使用缩写(大多数缩写都不能明确字段含义);
  • 字段不要大小写混用(想要具有可读性,多个英文单词可使用下划线形式连接);
  • 字段名不要使用保留字或者关键字;
  • 保持字段名和类型的一致性;
  • 慎重选择数字类型;
  • 给文本字段留足余量;

2、系统特殊字段处理及建成后建议

  • 添加删除标记(例如操作人、删除时间);
  • 建立版本机制;

3、表结构合理性配置

  • 多型字段的处理,就是表中是否存在字段能够分解成更小独立的几部分(例如:人可以分为男人和女人);
  • 多值字段的处理,可以将表分为三张表,这样使得检索和排序更加有调理,且保证数据的完整性!

4、其它建议

  • 对于大数据字段,独立表进行存储,以便影响性能(例如:简介字段);
  • 使用varchar类型代替char,因为varchar会动态分配长度,char指定长度是固定的;
  • 给表创建主键,对于没有主键的表,在查询和索引定义上有一定的影响;
  • 避免表字段运行为null,建议设置默认值(例如:int类型设置默认值为0)在索引查询上,效率立显;
  • 建立索引,最好建立在唯一和非空的字段上,建立太多的索引对后期插入、更新都存在一定的影响(考虑实际情况来创建);