形容相思之苦的句子 相思的苦句子唯美简短
你现在阅读的是一篇关于形容相思之苦的句子的文章,里面有丰富多彩的内容,还有给你准备相思的苦句子唯美简短和形容相思之苦的句子的精彩内容哦。
形容相思之苦的句子 相思的苦句子唯美简短
好想附在你的耳畔,轻声告诉你,我好想你,一别成殇,对你的惦记从未放下。
好想,踏一缕清风,轻轻走进你的世界里,看看你的样子,听听你的声音,向你诉说我一往而深的痴迷。
一份爱,还似从前一般深挚,却只能以一种寂寞的方式静默无语。
自你离去,我掩藏了所有痴心的话语,无声无息的爱着你。
那些说不出的爱恋,都压抑在心底,你不来,爱就是一辈子静默无声的秘密。
想你,念你,圈地为牢恋你,执迷不悟念你,我爱你
时光一日一日,一年一年,在悄无声息中流逝。
逝水流年,漂浅了太多记忆,却未曾让我放下你,一遇倾心,一生爱你,一朝别离,一世想你。
你离开后,我为自己筑起一座心牢,将你的记忆长锁在我的心牢里,别人走不进来,我也不舍得将你忘记。
为你执迷不悟,是我自己愿意,哪怕相思再苦,我也甘之若饴。
有幸遇见你,深深爱着你,无论你在哪里,你都是我心中最特别的存在,今生缘分断了,还有相思情牵。
亲爱的,我爱你!这一句我爱你,今生今世,我只说给你。
曲终人散,人去念依然
听过世间最无奈的话语:
蝴蝶为花碎,花却随风飞,花舞花落泪,花落为谁悲。
蝶恋花,为花醉,为花舞,奈何,花却随风飞,为风痴,为风悲。
世间情缘又何尝不是如此,深爱之人未必能够相守,情深至极未必可以相依。
感慨,今生情深缘浅,无缘与最深爱的你相依相伴,那缘曲终人散,对你的深情却留在心间,一念情深,一生沉沦。
为你,我倾尽了世间最真的爱,为你,我流过了今生最无奈的眼泪。
明明知道,若是缘分散了,思念还在,眉间心上的思念会苦了自己,可偏偏想你总是心不由己,爱你总是情难自抑。
我真的爱你,断了情缘,断不开思念,曲终人散,人去念依然。
真的想你,寄一封信给你,心中满满都是我的思念
想你,念你,却不能去看看你,因为我怕,怕我的冒昧会带给你困扰。
爱你,恋你,却不能打电话给你,因为我怕,怕我会压抑不住内心涌动的相思。
相思的话语不能说,对你的爱恋放不下,情深痴痴,痴念深深,只能深深地压抑在自己心底,藏成心底最深的秘密。
我的秘密就是想你,一个人孤单地想,寂寞的念,在风中想,在月下念,春来的时候想,秋尽的时候念……。
想你,想你,想你,想你,我以为我能忘记你,却要用整整一个余生去想你。
想你,想你,想你,想你,我以为我能不想你,却发现,“晓看天色暮看云,行也是你,坐也是你”。
用心爱过的人,就算无缘夫妻,也会在心里铭记一辈子;走进心中的爱,就算不能再相见,也会在梦中续写爱的永远。
亲爱的,我真的想你,真的真的好想你,寄一封信给最爱的你,信中满满都是我对你的相思。
想你,念你,就算今生不能朝朝暮暮,你也是我永恒的相思。
免费英语句子分析器(ElasticSearch原理知识点和整体结构详解)
ElasticSearch整体结构
通过上文,在通过图解了解了ES整体的原理后,我们梳理下ES的整体结构
- 一个 ES Index 在集群模式下,有多个 Node (节点)组成。每个节点就是 ES 的Instance (实例)。
- 每个节点上会有多个 shard (分片), P1 P2 是主分片, R1 R2 是副本分片
- 每个分片上对应着就是一个 Lucene Index(底层索引文件)
- Lucene Index 是一个统称由多个 Segment (段文件,就是倒排索引)组成。每个段文件存储着就是 Doc 文档。commit point记录了所有 segments 的信息
补充:Lucene索引结构
上图中Lucene的索引结构中有哪些文件呢?
更多文件类型可参考
文件的关系如下:
补充:Lucene处理流程
上文图解过程,还需要理解Lucene处理流程, 这将帮助你更好的索引文档和搜索文档。
创建索引的过程:
- 准备待索引的原文档,数据来源可能是文件、数据库或网络
- 对文档的内容进行分词组件处理,形成一系列的Term
- 索引组件对文档和Term处理,形成字典和倒排表
搜索索引的过程:
- 对查询语句进行分词处理,形成一系列Term
- 根据倒排索引表查找出包含Term的文档,并进行合并形成符合结果的文档集
- 比对查询语句与各个文档相关性得分,并按照得分高低返回
补充:ElasticSearch分析器
上图中很重要的一项是语法分析/语言处理, 所以我们还需要补充ElasticSearch分析器知识点。
分析 包含下面的过程:
- 首先,将一块文本分成适合于倒排索引的独立的 词条 ,
- 之后,将这些词条统一化为标准格式以提高它们的“可搜索性”,或者 recall
分析器执行上面的工作。 分析器 实际上是将三个功能封装到了一个包里:
- 字符过滤器 首先,字符串按顺序通过每个 字符过滤器 。他们的任务是在分词前整理字符串。一个字符过滤器可以用来去掉HTML,或者将 & 转化成 and。
- 分词器 其次,字符串被 分词器 分为单个的词条。一个简单的分词器遇到空格和标点的时候,可能会将文本拆分成词条。
- Token 过滤器 最后,词条按顺序通过每个 token 过滤器 。这个过程可能会改变词条(例如,小写化 Quick ),删除词条(例如, 像 a, and, the 等无用词),或者增加词条(例如,像 jump 和 leap 这种同义词)。
Elasticsearch提供了开箱即用的字符过滤器、分词器和token 过滤器。 这些可以组合起来形成自定义的分析器以用于不同的目的。
内置分析器
Elasticsearch还附带了可以直接使用的预包装的分析器。接下来我们会列出最重要的分析器。为了证明它们的差异,我们看看每个分析器会从下面的字符串得到哪些词条:
"Set the shape to semi-transparent by calling set_trans(5)"
- 标准分析器
标准分析器是Elasticsearch默认使用的分析器。它是分析各种语言文本最常用的选择。它根据 Unicode 联盟 定义的 单词边界 划分文本。删除绝大部分标点。最后,将词条小写。它会产生
set, the, shape, to, semi, transparent, by, calling, set_trans, 5
- 简单分析器
简单分析器在任何不是字母的地方分隔文本,将词条小写。它会产生
set, the, shape, to, semi, transparent, by, calling, set, trans
- 空格分析器
空格分析器在空格的地方划分文本。它会产生
Set, the, shape, to, semi-transparent, by, calling, set_trans(5)
- 语言分析器
特定语言分析器可用于 很多语言。它们可以考虑指定语言的特点。例如, 英语 分析器附带了一组英语无用词(常用单词,例如 and 或者 the ,它们对相关性没有多少影响),它们会被删除。 由于理解英语语法的规则,这个分词器可以提取英语单词的 词干 。
英语 分词器会产生下面的词条:
set, shape, semi, transpar, call, set_tran, 5
注意看 transparent、 calling 和 set_trans 已经变为词根格式。
什么时候使用分析器
当我们 索引 一个文档,它的全文域被分析成词条以用来创建倒排索引。 但是,当我们在全文域 搜索 的时候,我们需要将查询字符串通过 相同的分析过程 ,以保证我们搜索的词条格式与索引中的词条格式一致。
全文查询,理解每个域是如何定义的,因此它们可以做正确的事:
- 当你查询一个 全文 同时, 会对查询字符串应用相同的分析器,以产生正确的搜索词条列表。
- 当你查询一个 精确值 域时,不会分析查询字符串,而是搜索你指定的精确值。
举个例子
ES中每天一条数据, 按照如下方式查询:
GET /_search?q=2023 # 12 resultsGET /_search?q=2023-09-15 # 12 results !GET /_search?q=date:2023-09-15 # 1 resultGET /_search?q=date:2023 # 0 results !
为什么返回那样的结果?
- date 域包含一个精确值:单独的词条 2023-09-15。
- _all 域是一个全文域,所以分词进程将日期转化为三个词条: 2023, 09, 和 15。
当我们在 _all 域查询 2023,它匹配所有的12条推文,因为它们都含有 2023 :
GET /_search?q=2023 # 12 results
当我们在 _all 域查询 2023-09-15,它首先分析查询字符串,产生匹配 2023, 09, 或 15 中 任意 词条的查询。这也会匹配所有12条推文,因为它们都含有 2023 :
GET /_search?q=2023-09-15 # 12 results !
当我们在 date 域查询 2023-09-15,它寻找 精确 日期,只找到一个推文:
GET /_search?q=date:2023-09-15 # 1 result
当我们在 date 域查询 2023,它找不到任何文档,因为没有文档含有这个精确日志:
GET /_search?q=date:2023 # 0 results !
免费英语句子分析器(电商搜索系统精讲系列三步曲2)
编辑导读:在电商软件中搜索一款产品,页面中会出现很多相关产品的展示。这些页面是如何展示呢?为什么会这样展示?本文作者以电商产品为例,对其页面排序系统进行分析,希望对你有帮助。
01 排序的场景模型
上篇文章我们针对一个电商搜索系统的业务以及召回分析器和模型的分析,比如当用户在淘宝APP搜索框中输入搜索关键词“2023年新款花式促销女士连衣裙”,搜索系统会通过分析器和各种模型来理解用户的搜索意图,进而达到召回商品的目的(这块的原型将在“电商搜索系统精讲系列三步曲”的下篇会push给大家);
那么思考一个问题,用户搜索“2023年新款花式促销女士连衣裙”之后,页面怎么展示,为什么会这么展示?依据是什么,如下图?
这个就是我们今天要去讲的内容,往下看:
在分析这块的内容之前,同样,我依然举现实生活中的场景模型:
某公司产品总监A需要招聘具有丰富教育中台行业经验的产品经理,在BOSS直聘的岗位描述JD(Job Description)增加了要具备教育中台行业的经验的招聘要求,于是有以下求职者去面试:
- 应聘者B:有教育行业经验,但无中台产品建设经验;
- 应聘者C:有教育行业经验,但工作年限比较短,不够丰富;
- 应聘者D:有中台产品建设经验,但无教育行业经验;
- 应聘者E:有丰富的教育中台行业经验,但是之前做的是解决方案,并非产品经理岗;
那么现在,假设你作为该公司的产品总监,你该怎么选?先不要看下面,先思考;
答案其实也很简单,你一定是挑选一个适合该岗位要求的吧,那么什么才叫适合,评判的依据是什么?你作为产品总监究竟怎么对这四个求职者进行评估?
现在有些大公司采购了线上招聘系统,人力资源HR和产品总监把对这四位求职者的面试结论以文字的方式直接录入到这个招聘系统,系统就会给出一个建议分,这个建议分值提供给产品总监和HR人员进行决策评估和参考,当然没有这个线上招聘系统也没关系,最土的办法就是下面这种,用手填写面试评估表,用手打分,只不过这种方式的打分更多带有主观色彩。
所以最后的结论就是对每个求职者进行打分,然后通过打分来对B、C、D、E四名求职者进行排序,排序第一、第二、第三及第四,最后择优录用;
好,上面说的是招聘的工作,想一想,我们每年高考录取是不是也是这种方式来进行择优录取,同样的场景模型,我们尝试搬迁到线上,应用在召回商品的排序上,接着看:
那么问题来了,同样的场景模型搬迁到线上,就会涉及到对召回的商品打分怎么打的问题,这个是核心,人类有大脑可以用于主观判断,但电脑没有眼睛没有感官系统,没法等同于人类那样去思考,所以我们需要做的就是给他输入一系列的打分规则,电脑就能打分,就能对召回的商品进行排序,从而实现我们的目标,接下来我们看排序的策略;
02 排序策略
大家回想之前浙江卫视的中国好声音节目,那些在电视荧幕上看到的唱歌选手也一定是提前开始海选,然后逐层选拔通过才会参加电视上的唱歌比赛吧,如果没有海选这个环节呢,每个人只要报名都可以直接在电视上唱那么一曲,那岂不是要把浙江卫视那些工作人员累死,所以选手是通过海选,逐层比赛,一关一关的通过,最后挑选出表现优秀的前100名参与电视上的唱歌比赛;
我们采用同样的套路,召回的商品(因为这个量级也是非常巨大的)先海选,再去精选,业内很多人称海选为粗选,所以召回的商品先要进行粗选,通过粗选把可能满足用户意图并且是相对优质的商品(比如有一万个)全部筛选出来,再去优化(一万个召回的商品精选排序)这个选择的结果,最后把选出来的前1000(只是假设)个商品进行排序展示给用户;
搜索引擎本身对于检索性能要求比较高,所以需要采用上面说的两个阶段排序过程:粗排和精排。粗排就是上面说的海选,从检索结果中快速找到优质的商品,取出TOP N个结果再按照精排进行打分,最终返回最优的结果给用户。所以一般在搜索系统中,粗排对性能影响比较大,精排对最终排序效果影响比较大,因此,粗排要求尽量简单有效,只提取数据库表中的关键因子(字段)即可,关键的问题在于打分怎么打,下面将给大家介绍常见的打分策略:
我们首先引入一个新的概念—-表达式计算法
所谓表达式计算法:通俗的讲,就是通过不同的计算公式来运算每个被召回的产品和用户意图的相关度,这个相关度某种意义上讲就是打的分数,业内普遍称这个过程为相关算分,一般常见的计算公式比如基本运算(算术运算、关系运算、逻辑运算、位运算、条件运算)、数学函数和排序特征(feature)等。
基本运算:
数学函数:
以上两个函数比较简单,高等数学里面都有的内容,这里不再细说,下面来看下上面提到的粗排常用的几个函数(以下为天猫搜索为例):
关键词相似文本分Text similarity函数:用于计算用户输入的关键词文本与召回的商品相关度,值越大,则相关度越高;
召回商品距离现在的时间GoodsTime函数:用于计算召回的商品距离现在的时间,一般取值为(0,1)之间,一般值越大,表商品距离现在时间越近,越容易被展示在用户的界面;
类目预测函数CategoryPredic:用于计算用户输入的关键词与商品类目的相关度,关于类目预测这里需要仔细说明下:
所谓类目预测,指的是通过计算机的算法去预测搜索的关键词与商品
类目的相关程度,我们举个例子,当用户在淘宝APP搜索框中输入关键词“苹果”,则类目预测会计算商品所属类目与输入的苹果这个关键词的相关度,类目与关键词的相关度越高,商品就获得了越高的排序得分,也就是上文说到的相关算分值就越高,从而这个商品就会排在越前面,借助下面这两张图,就更好理解了:
第一张图:搜索的关键字是“苹果”,既有手机类的商品也有食物类的商品,左图就是典型的没有使用类目预测模型来打分,所以把食物类的苹果也召回并且优先排序在前面,右图是使用后类目预测模型后的打分排序效果;
所以我们在做产品原型设计的时候也要考虑搜索的关键词与商品类目的相关程度,需要在原型的设计里面增加类目预测的模型的设计;
再来回过头看,我前面讲的,排序首选要进行海选也就是粗排,再针对粗排后的商品结果进行精排,粗排已经讲了,精排怎么排?
同样是要通过函数去计算搜索的关键词与商品的相关度,常见的函数有:
文本相关度函数:
- text_relevance: 关键词在字段上的商品匹配度
- field_match_ratio:获取某字段上与查询词匹配的分词词组个数与该字段总词组个数的比值
- query_match_ratio:获取查询词中(在某个字段上)命中词组个数与总词组个数的比值
- fieldterm_proximity: 用来表示关键词分词词组在字段上的紧密程度
- field_length:获取某个字段上的分词词组个数
- query_term_count: 返回查询词分词后词组个数
- query_term_match_count:获取查询词中(在某个字段上)命中文档的词组个数
- field_term_match_count:获取文档中某个字段与查询词匹配的词组个数
- query_min_slide_window:查询词在某个字段上命中的分词词组个数与该词组在字段上最小窗口的比值
地理位置相关性:
- distance: 获取两个点之间的球面距离。一般用于LBS的距离计算。
- gauss_decay,使用高斯函数,根据数值和给定的起始点之间的距离,计算其衰减程度
- linear_decay,使用线性函数,根据数值和给定的起始点之间的距离,计算其衰减程度
- exp_decay,使用指数函数,根据数值和给定的起始点之间的距离,计算其衰减程度
时效性:
- timeliness: 时效分,用于衡量商品的新旧程度,单位为秒
- timeliness_ms: 时效分,用于衡量商品的新旧程度,单位为毫秒
算法相关性:
- category_score:类目预测函数,返回参数中指定的类目字段与类目预测query的类目匹配分
- popularity:人气分,用于衡量物品的受欢迎程度
功能性:
- tag_match: 用于对查询语句和商品做标签匹配,使用匹配结果对商品进行算分加权
- first_phase_score:获取粗排表达式最终计算分值
- kvpairs_value: 获取查询串中kvpairs子句中指定字段的值
- normalize:归一化函数,根据不同的算分将数值归一化至[0, 1]
- in/notin : 判断字段值是否(不)在指定列表中
以上函数大家不用去研究细节,看看函数的中文解释就好,帮助理解和消化,知道精排的算分怎么统计、哪些维度去统计即可,如果依然不理解的,可以跟我一起交流;
说到现在大家一定很好奇,为什么用户最关心的商品热度没有提到,不着急不着急,接下来,我们就要针对搜索热度比较高的商品一般怎么排序,引入一个新的概念—–人气模型;
上面说的类目预测模型是要实时去计算,而人气模型可以在离线的时候进行计算,一般也叫离线计算模型,这种模型也是淘宝和天猫搜索最基础的排序算法模型。
人气模型会计算量化出每个商品的静态质量以及受欢迎的程度的值,这个值称之为商品人气分,最开始人气模型是来自淘宝的搜索业务,但其实这个模型对于其他的搜索场景也有很强的通用性,在非商品搜索场景中通过人气模型也可以计算出被索引的商品的受欢迎程度,比如某个论坛,可以通过人气模型排序搜索比较多的帖子,把这些帖子内容优先展示给用户;
那么对于一个商品而言,这个人气模型究竟怎么计算,毕竟系统的目标是通过这个模型来计算商品的热度,进而打分排序,你说对吧;
一般情况下,人气模型从四个维度去计算分值,具体如下:
第一个维度:实体维度;
比如:商品、品牌、商家、类目等。
第二个维度:时间维度;
比如:1天、3天、7天、14天、30天等。
第三个维度:行为维度;
第四个维度:统计维度;
每个特征从以上4个维度中各取一到两个进行组合,再从历史数据中统计该组合特征最终的特征值:
比如:
- 商品(实体)最近1天(时间)的曝光(行为)量(统计指标);
- 商品所在店铺(实体)最近30天(时间)的销量(行为类型+统计维度)等等。
由以上方法产生的结果数量级,等同于去计算4个维度的笛卡尔积,再对笛卡尔积的算分高低进行排序;
好了,说到现在关于召回的商品排序所采用的算法目前我所了解的就这么多,当然能力有限,有些搜索的细节依然需要进一步去摸索;
03 召回与排序总结
我们来对上一篇文章和今天讲的内容简单的做个总结,当用户在淘宝APP搜索框中输入“2023年新款花式促销女士连衣裙”时,搜索引擎系统首先要去理解用户的意图,理解的方式就是上篇文章提到的分析器,通过对语义的理解、命名实体识别、拼写纠错、停止词模型等手段去理解用户的意图,进而通过这个意图计算机去到后台数据库中检索符合意图的所有商品,当商品被检索出来之后,搜索引擎系统首先要通过各类函数和模型对商品进行粗排,再对粗排的结果进行精排,精排的依据就是上面的函数和模型,当然还有类目预测模型和人气模型,这个就是大概的流程;
依然没有结束,首先来看下面这张图:
想一想,上面左图中的热搜底纹和热搜列表是怎么来的、右图中的下拉提示又是这么出现的?这个就是原计划需要在今天跟大家讲的引导排序内容;
04 预告
题图来自Pexels,基于CC0协议
免费英语句子分析器(阿里大佬私人珍藏的MySQL笔记)
基本架构
MySQL 基本架构示意图如下:
MySQL 大体可以分为两部分:Server 层和存储引擎层(功能跟日常开发中的 Service 层和与 DAO 层有点像,可以对比理解)。
Server 层
主要有连接器(Connector)、查询缓存(Cache)、分析器(Parser)、优化器(Optimizer)和执行器(Executor)等,包括了 MySQL 的大部分核心功能以及所有内置函数(日期、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,例如存储过程、触发器、视图等。
存储引擎层
存储引擎(Storage Engine)层主要负责数据的存储和提取,它是直接和磁盘打交道的,以插件形式存在,例如 InnoDB、MyISAM、Memory 等多种存储引擎。
从 MySQL 5.5.5 开始,InnoDB 成为了默认的存储引擎。
Server 层
连接器
主要功能:跟客户端建立(TCP)连接、获取权限、维持和管理连接。
若用户认证通过,连接器会查询权限列表获取该用户的权限,之后该连接的权限判断都基于此(因此,一个用户建立连接后,即使被修改了权限也不会影响已存在连接的权限,只有重新建立连接后才生效)。
客户端建立连接示例(分别为失败和成功):
# 连接失败(密码错误)$ mysql -uroot -pEnter password:ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
# 连接成功$ mysql -uroot -pEnter password:Welcome to the MySQL monitor. Commands end with ; or \g.Your MySQL connection id is 7Server version: 5.7.19 MySQL Community Server (GPL)Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.Oracle is a registered trademark of Oracle Corporation and/or itsaffiliates. Other names may be trademarks of their respectiveowners.Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.mysql>
进入 MySQL 后可以用如下命令查看连接状态:
# 查看连接状态mysql> show processlist;+----+------+-----------+------+---------+------+----------+------------------+| Id | User | Host | db | Command | Time | State | Info |+----+------+-----------+------+---------+------+----------+------------------+| 6 | root | localhost | NULL | Sleep | 81 | | NULL || 7 | root | localhost | NULL | Query | 0 | starting | show processlist |+----+------+-----------+------+---------+------+----------+------------------+2 rows in set (0.00 sec)
在 Command 列中,Sleep 表示该连接是空闲的。
连接成功后是有超时时间的,若太长时间没有操作会断开连接,由参数 wait_timeout 控制,默认为 8 小时,
查询缓存
主要功能:缓存查询结果。
连接建立之后,就可以进行查询了。
在一个查询语句中,会先到缓存中查询之前是否查询过该语句,若存在则直接返回对应的结果;否则继续执行后面的流程。
PS: 此处理流程可以类比我们在项目中使用 Redis 等作为缓存的操作,即先查缓存,再查 DB。
也可以通过使用 SQL_CACHE 显式指定使用查询缓存(这里的 id 并非主键),例如:
SELECT SQL_CACHE * FROM t1 WHERE id=10;
查询缓存的优缺点:
1. 优点:查询命中缓存时效率很高。
2. 缺点:缓存失效非常频繁,只要有对一个表的更新,该表所有的查询缓存都会被清空。
由于上述优缺点,可以发现缓存适用于静态表或更新较少的表,对于更新较频繁的表并不适用。值得一提的是,MySQL 8.0 版本已删除了查询缓存功能,可见该功能比较鸡肋。
分析器
主要功能:对 SQL 语句进行词法分析和语法分析。
1. 词法分析:分词操作,由于我们传递给 MySQL 的 SQL 语句实质上就是一个字符串,MySQL 需要将其拆分成一个个的分词(语法树)并进行识别,例如识别“SELECT”、“UPDATE”等关键字,将 t1 识别为一张表,将 id 识别为一列等。
2. 语法分析:拿到词法分析的结果,并根据语法规则判断 SQL 语句是否合法。若语法错误,则会收到如下错误提示:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ...
优化器
主要功能:优化 SQL 语句。
经过了分析器之后,MySQL 已经知道了我们提交的 SQL 语句是干嘛的。但为了提高执行效率,它并非完全按照我们的 SQL 语句执行,而要进行一系列优化。例如,当表中有多个索引时决定使用哪个索引;多表关联(JOIN)查询时决定表连接的顺序等等。
PS: 有点类似于 JVM 执行 Java 代码时的操作。即,JVM 并非完全按照代码的先后顺序来执行的,它会调整一些代码的执行顺序以提高效率,只是保证最终结果与代码顺序执行的效果一致。
执行器
主要功能:执行 SQL 语句。
MySQL 知道了我们要做什么,并且进行了优化,接下来就要开始执行了。执行之前,会判断你对该表是否有查询的权限,若有权限则继续执行;否则会返回如下错误(这里以 SELECT 操作为例,其他类似):
SELECT command denied to user 'user'@'localhost' for table 't1'
为什么到这一步才进行权限检查呢?
是因为有时候 SQL 语句要操作的表不只是 SQL 字面上的那些(例如触发器要在执行过程中才能确定),因此权限检查在这里进行。
存储引擎
以上述 SELECT 语句为例,执行步骤如下:
1. 调用 InnoDB 引擎接口取 t1 表的第一行,判断 id 是否为 10,若不是则跳过;否则将这一条记录存在结果集中;
2. 调用存储引擎接口读取“下一行”,判断逻辑同步骤 1,直至读取到表的最后一行;
3. 执行器将上述遍历过程中所有满足条件的记录作为结果集返回给客户端。
MySQL 查看所有存储引擎:
mysql> show engines;+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+| Engine | Support | Comment | Transactions | XA | Savepoints |+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+| InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES || MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO || MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO || BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO || MyISAM | YES | MyISAM storage engine | NO | NO | NO || CSV | YES | CSV storage engine | NO | NO | NO || ARCHIVE | YES | Archive storage engine | NO | NO | NO || PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO || FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL |+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+9 rows in set (0.00 sec)
其中 Support 表示该引擎是否可用(DEFAULT 表示默认值);Comment 是描述信息;Transactions 表示是否支持事务;XA 表示是否支持分布式事务;Savepoints 表示是否支持回滚。
其中最为常用的就是 InnoDB 引擎,而且它也是默认的。其他常见的还有 MyISAM 和 Memory 引擎,这三种引擎简单对比如下:
MyISAMInnoDBMemory存储限制256TB64TB有事务???索引???锁表锁行级锁表锁外键???
小结
MySQL 的整体架构主要分为两部分:Server 层和存储引擎层。
Server 主要有连接器、查询缓存、分析器、优化器和执行器等,包括了 MySQL 的大部分核心功能以及所有内置函数,所有跨存储引擎的功能都在这一层实现,例如存储过程、触发器、视图等。
存储引擎层:负责数据的存储和提取,以插件形式存在,例如 InnoDB (MySQL 5.5.5 以后默认的存储引擎)、MyISAM、Memory 等多种存储引擎。
PS: 发现一个现象,许多东西在学的时候觉得不难,但是如果自己不去做笔记的话就很容易忘记。因此就需要用自己的语言去表达出来,这样更能促进思考,也能进一步“内化”到自己的知识体系中。
索引
简单来说,索引的出现是为了提高查询效率,就像书的目录一样。MySQL 的索引是在「存储引擎」层实现的,因此没有统一的标准,同一种类型的索引,在不同存储引擎之间实现可能也不同。本文主要分析 InnoDB 存储引擎的索引结构。
索引模型
索引模型就是索引的实现形式(也可以理解为索引的数据结构),常见的索引模型有下面三种:
1. 哈希表(散列表)
键值对形式(类似 Java 中的 HashMap)
优点:新增速度快;
缺点:无序,区间查询速度很慢(全表扫描)。
适用场景:只有等值查询的情况(例如 Memcached 等一些 NoSQL 引擎)。
2. 有序数组
优点:等值查询和范围查询速度都很快。
缺点:更新成本太高(插入的记录在中间时,需要移动后面的所有记录,可类比在数组中间位置插入元素的操作)。
适用场景:静态存储引擎(比如不再修改的历史数据)。
3. 搜索树(N 叉树)
优点:读写快,适配磁盘的访问模式。
B+ 树就是其中的一种,也是 InnoDB 存储引擎的索引模型。
InnoDB 记录的存储结构
数据页
在 InnoDB 引擎中,会将数据划分为若干个「页」,「页」是磁盘和内存之间交互的基本单位,页的大小一般为 16KB。即:一般情况下,一次最少从磁盘中读取 16KB 的数据到内存中,一次至少把内存中 16KB 的数据刷新到磁盘中。
向一个数据页中插入记录的过程如图所示:
数据页中分为几个部分,其中 User Records 部分为存储记录的空间(其他部分存储数据页的其他信息,这里暂不详述),插入过程大致如下:
1. 未插入记录时,User Records 部分不存在;
2. 当插入记录时,会从 Free Space 部分划分出空间存储记录;
3. 当 Free Space 空间用完时,也就是该数据页的空间用完了,需要分配新的数据页存储(页分裂)。
记录的结构
在 InnoDB 引擎中,一条记录的存储结构如图所示:
PS: 其中橙色部分 (c1, c2, c3) 是表中的列,且 c1 为主键,下图亦是如此。
也就是说,数据页中记录的数据,除了一条记录本身,还有变长字段列表、NULL 值列表、记录头信息等其他信息,这样才是在数据页中的一条完整记录。
数据页中多条记录之间的关系示意图:
即,每个页中保存了许多条记录,并且每条记录指向下一条记录(根据主键顺序,类似单链表结构)。此外还记录了该页中的最小和最大记录(也是根据主键顺序)。
不仅如此,这些记录还会几条(1~8)分为一个组,并且把组内最大的主键值提取到一个槽(slot)中,用来实现快速(二分)查找,示意图如下:
页内查找记录
以上面的数据页为例,若要查找主键值为 5 的记录,过程如下(二分查找):
1. 计算中间槽的位置:(0+4)/2=2,因此查找槽 2,而它对应记录的主键为 8,5<8,重新计算;
2. 重新计算,(0+2)/2=1,查找槽 1,对应记录的主键值为 4,5>4,因此查找的记录在槽 2 中;
3. 遍历槽 2 对应的分组,查找主键为 5 的记录。
因此在一个数据页中查找指定主键值的记录过程大致分为两步:
1. 通过二分查找确定记录所在的槽;
2. 遍历该槽所在组中的各个记录(通过记录的 next_record)。
由于槽内数据很少(不超过 8 条),因此遍历的成本较低。
聚簇索引&二级索引
根据叶子节点的内容,索引类型可分为「聚簇索引」(Clustered Index)和「二级索引」(Secondary Index)。
1. 聚簇索引
在 InnoDB 存储引擎中,聚簇索引也称为「主键索引」,表都是根据主键顺序组织存放的,这种存储方式的表称为索引组织(Index Organized Table)表(索引即数据,数据即索引)。一张表只能有一个主键索引。
聚簇索引的示意图如下(该结构就是一棵 B+ 树):
图中结构分为三层,其中上面的两层(即非叶子节点,页 33、页 30 和页 32)为索引层,保存的是索引信息;第三层(叶子节点)为数据层。在主键索引中,叶子节点保存的是完整的记录(以数据页为单位)。
PS: 存储节点的空间可能是不连续的,但是,同一层的节点是有前后顺序的,它们之间以「双向链表」的形式连接。
在索引树中查找一条记录的大致过程如下(仍以查找主键值为 5 的记录为例):
1. 先查找根节点,即页 33,页 30 中的主键范围是 [1, 320),而页 32 中主键大于等于 320,因此定位到 页 30;
2. 再查找页 30,同样的方法定位到页 28;
3. 根据上面「页内查找记录」的方式在页 28 中查找。
2. 二级索引
InnoDB 中,二级索引的叶子节点存储的是主键的值。二级索引也称为「非聚簇索引」、「非主键索引」。一张表可以有多个二级索引。其中,以单列作为二级索引的又称「单列索引」,以多列作为索引的又称「联合索引」或者「组合索引」。
二级索引的示意图如下:
该结构与聚簇索引类似,也是一棵 B+ 树。
与聚簇索引的不同之处主要在于第三层,也就是叶子节点,在二级索引中,叶子节点保存的是主键的值。
二级索引中的查找过程与聚簇索引中查找类似。
不同的是,由于二级索引保存的是索引列和主键列,若查找的数据包含索引和主键之外的内容,则需要先找出主键值,然后再根据主键的值到聚簇索引中查找完整记录,该过程称为「回表」。
值得注意的是,上述查找都是在有索引的情况下进行的,如果没有索引呢?则会进行全表扫描,这样当数据量较大时,效率会非常低。这也是索引出现的主要原因。
区别与联系(InnoDB 存储引擎)
1. 聚簇索引和二级索引都需要占用磁盘空间,每一个索引都对应一棵索引树;
2. 二者都是 B+ 树结构,数据都存储在叶子节点(非叶子节点不保存数据);
3. 聚簇索引的叶子节点保存的是完整记录,二级索引保存的是主键的值;
4. 在一张表中,聚簇索引只能有一个,二级索引可以有多个(即多个索引树)。
根据这几点比较也可以发现,索引虽然可以提高查找效率,但也有缺点。如果有多个索引,当修改数据时索引也要同步进行更新,这样会降低操作的效率;而且索引也会占用磁盘空间。因此,索引并非越多越好。
InnoDB 引擎主键选择
在 InnoDB 中,每张表都有个主键(Primary Key),如果在建表时没有显式地定义主键,则 InnoDB 引擎会按照如下方式选择或创建主键:
1. 首先判断表中是否有非空的唯一索引(Unique NOT NULL),若有,则该列即为主键(当表中有多个非空唯一索引时,InnoDB 存储引擎将选择建表时第一个定义的非空唯一索引为主键);
2. 若不符合上述条件,InnoDB 存储引擎自动创建一个 6 字节大小的隐藏列(row_id)作为主键。
因此,建表时最好显式指定主键。
索引优缺点
主要优缺点如下(可通过上述存储结构分析理解):
优点
1. 可以提高数据检索效率,降低数据库 IO 成本;
2. 对记录进行排序,降低 CPU 消耗(被索引的列会自动进行排序),可以提高排序和分组查询的效率。
缺点
1. 索引会占用磁盘空间;
2. 降低更新效率(更新操作会同步更新索引)。
索引使用场景
需要创建索引的场景
1. 主键自动建立唯一索引;
2. 频繁作为查询条件的字段应该创建索引;
3. 多表关联查询中,关联字段应该创建索引(ON 两边都要创建);
4. 查询中排序的字段,应该创建索引;
5. 统计或者分组。
不需要使用索引的场景
1. 表记录太少;
2. 频繁更新;
3. 查询字段使用频率不高。
PS: 这里只是概括了一些常见的优缺点和使用场景,可以根据前面对索引的结构和特点的分析对比理解。
小结
简单来说,索引可以理解为书的目录。
索引的主要作用是为了提高查找效率;但索引也有缺点,并非越多越好,需要根据实际情况决定如何创建合适的索引。
免费英语句子分析器(深入理解SQL原理)
本篇文章将通过一条 SQL 的执行过程来介绍 MySQL 的基础架构。
首先有一个 user_info 表,表里有一个 id 字段,执行下面这条查询语句:
select * from user_info where id = 1;
返回结果为:
+----+----------+----------+--------+------+---------------------+---------------------+| id | username | password | openid | role | create_time | update_time |+----+----------+----------+--------+------+---------------------+---------------------+| 1 | 武培轩 | 123 | 1 | 1 | 2023-08-29 00:29:08 | 2023-08-29 00:29:08 |+----+----------+----------+--------+------+---------------------+---------------------+
下面给出 MySQL 的基本架构示意图,可以看出 SQL 语句在 MySQL 的各个模块中的执行过程。
MySQL 基本架构
大体上,MySQL 分为 Server 层和存储引擎层两部分。
Server 层包括连接器、查询缓存、分析器、执行器等,以及所有的内置函数(如日期、时间、数学和加密函数等)和跨存储引擎的功能(如存储过程、触发器、视图)。
存储引擎层负责数据的存储和提取,支持 InnoDB、MyISAM、Memory 等多个存储引擎。MySQL 5.5.5 版本后默认存储存储引擎是 InnoDB。
1.连接器(Connector)
在查询 SQL 语句前,肯定要先建立与 MySQL 的连接,这就是由连接器来完成的。连接器负责跟客户端建立连接、获取权限、维持和管理连接。连接命令为:
mysql -h$ip -P$port -u$user -p
输入密码,验证通过后,连接器会到权限表里面查出你拥有的权限,之后这个连接里面的权限判断逻辑,都将依赖于此时读到的权限,一个用户成功建立连接后,即使管理员对这个用户的权限做了修改,也不会影响已经存在连接的权限,修改完后,只有再新建的连接才会使用新的权限设置。
连接完成后,如果你没有后续的动作,这个连接就处于空闲状态,你可以在 show processlist 命令中看到它。结果如下:
+----+------+----------------+------------------+---------+------+----------+------------------+| Id | User | Host | db | Command | Time | State | Info |+----+------+----------------+------------------+---------+------+----------+------------------+| 3 | root | localhost:2790 | NULL | Sleep | 5878 | | NULL || 4 | root | localhost:2791 | springcloud_sell | Sleep | 5838 | | NULL || 7 | root | localhost:2900 | springcloud_sell | Sleep | 5838 | | NULL || 10 | root | localhost:3627 | springcloud_sell | Query | 0 | starting | show processlist |+----+------+----------------+------------------+---------+------+----------+------------------+
客户端如果太长时间没动静,连接器就会自动将它断开;这个时间是由参数 wait_timeout 控制的,默认值是8小时。如果在连接被断开之后,客户端再次发送请求的话,就会收到一个错误提醒:Lost connection to MySQL server during query。
长连接和短连接
- 数据库里面,长连接是指连接成功后,如果客户端持续有请求,则一直使用同一个连接。
- 短连接则是指每次执行完很少的几次查询就断开连接,下次查询再重新建立一个。
建立连接的过程通常是比较复杂的,建议在使用中要尽量减少建立连接的动作,尽量使用长连接。但是全部使用长连接后,有时候 MySQL 占用内存涨得特别快,这是因为 MySQL 在执行过程中临时使用的内存是管理在连接对象里面的。这些资源会在连接断
开的时候才释放。所以如果长连接累积下来,可能导致内存占用太大,被系统强行杀掉(OOM),从现象看就是 MySQL 异常重启了。
怎么解决这个问题呢?可以考虑以下两种方案:
- 定期断开长连接。使用一段时间,或者程序里面判断执行过一个占用内存的大查询后,断开连接,之后要查询再重连。
- MySQL 5.7 以上版本,可以在每次执行一个比较大的操作后,通过执行 mysql_reset_connection 来重新初始化连接资源。这个过程不需要重连和重新做权限验证,但是会将连接恢复到刚刚创建完时的状态。
2.查询缓存(Query Cache)
在建立连接后,就开始执行 select 语句了,执行前首先会查询缓存。
MySQL 拿到查询请求后,会先查询缓存,看是不是执行过这条语句。执行过的语句及其结果会以 key-value 对的形式保存在一定的内存区域中。key 是查询的语句,value 是查询的结果。如果你的查询能够直接在这个缓存中找到 key,那么这个
value 就会被直接返回给客户端。
如果语句不在查询缓存中,就会继续后面的执行阶段。执行完成后,执行结果会被存入查询缓存中。如果查询命中缓存,MySQL 不需要执行后面的复杂操作,就可以直接返回结果,会提升效率。
但是查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查询缓存都会被清空。对于更新压力大的数据库来说,查询缓存的命中率会非常低。如果业务中需要有一张静态表,很长时间才会更新一次。比如,一个系统配置表,那这张表上的查询才适合使用查询缓存。MySQL 提供了这种按需使用的方式。可以将参数 query_cache_type 设置成 DEMAND,对于默认的 SQL 语句都将不使用查询缓存。而对于你确定要使用查询缓存的语句,可以用 SQL_CACHE 显式指定,如下:
mysql> select SQL_CACHE * from user_info where id = 1;
MySQL 8.0 版本将查询缓存的功能删除了。
3.分析器(Analyzer)
如果查询缓存未命中,就要开始执行语句了。首先,MySQL 需要对 SQL 语句进行解析。
分析器先会做词法分析。SQL 语句是由多个字符串和空格组成的,MySQL 需要识别出里面的字符串分别是什么,代表什么。MySQL 从你输入的 select 这个关键字识别出来,这是查询语句。它也要把字符串 user_info 识别成表名,把字符串 id 识别成列名。之后就要做语法分析。根据词法分析的结果,语法分析器会根据语法规则,判断输入的 SQL 语句是否满足 MySQL 语法。
如果你 SQL 语句不对,就会收到 You have an error in your SQL syntax 的错误提醒,比如下面这个语句 from 写成了 form。
mysql> select * form user_info where id = 1;1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'form user_info where id = 1' at line 1
一般语法错误会提示第一个出现错误的位置,所以要关注的是紧接 use near 的内容。
4.优化器(Optimizer)
经过分析器的词法分析和语法分析后,还要经过优化器的处理。
优化器是在表里面有多个索引的时候,决定使用哪个索引;或者在一个语句有多表关联(join)的时候,决定各个表的连接顺序。比如你执行下面这样的语句,这个语句是执行两个表的 join:
mysql> SELECT * FROM order_master JOIN order_detail USING (order_id) WHERE order_master.pay_status = 0 AND order_detail.detail_id = 1558963262141624521;
既可以先从表 order_master 里面取出 pay_status = 0 的记录的 order_id 值,再根据 order_id 值关联到表 order_detail,再判断 order_detail 里面 detail_id 的值是否等于 1558963262141624521。
也可以先从表 order_detail 里面取出 detail_id = 1558963262141624521 的记录的 order_id 值,再根据 order_id 值关联到 order_master,再判断 order_master 里面 pay_status 的值是否等于 0。
这两种执行方法的逻辑结果是一样的,但是执行的效率会有不同,而优化器的作用就是决定选择使用哪一个方案。优化器阶段完成后,这个语句的执行方案就确定下来了,然后进入执行器阶段。
5.执行器(Actuator)
MySQL 通过分析器知道了要做什么,通过优化器知道了该怎么做,于是就进入了执行器阶段,开始执行语句。
开始执行的时候,要先判断一下你对这个表 user_info 有没有执行查询的权限,如果没有,就会返回没有权限的错误,如下所示 (如果命中查询缓存,会在查询缓存返回结果的时候,做权限验证。查询也会在优化器之前调用 precheck 验证权限)。
mysql> select * from user_info where id = 1;ERROR 1142 (42000): SELECT command denied to user 'wupx'@'localhost' for table 'user_info'
如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。比如我们这个例子中的表 user_info 中,id 字段没有索引,那么执行器的执行流程是这样的:
- 调用 InnoDB 引擎接口取这个表的第一行,判断 id 值是不是 1,如果不是则跳过,如果是则将这行存在结果集中;
- 调用引擎接口取下一行,重复相同的判断逻辑,直到取到这个表的最后一行。
- 执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果集返回给客户端。
对于有索引的表,第一次调用的是取满足条件的第一行这个接口,之后循环取满足条件的下一行这个接口。
数据库的慢查询日志中有 rows_examined 字段,表示这个语句执行过程中扫描了多少行。这个值就是在执行器每次调用引擎获取数据行的时候累加的。在有些场景下,执行器调用一次,在引擎内部则扫描了多行,因此引擎扫描行数跟 rows_examined 并不是完全相同的。
总结
主要通过对一个 SQL 语句完整执行过程进行讲解,介绍 MySQL 的逻辑架构,MySQL 主要包括连接器、查询缓存、分析器、优化器、执行器这几个模块。
点关注,不迷路!
以上内容是关于形容相思之苦的句子和相思的苦句子唯美简短的内容,小编幸苦为你编辑整理,喜欢的请点赞收藏把。