首页 文章 精选 留言 我的

精选列表

搜索[Linux内核],共10000篇文章
优秀的个人博客,低调大师

配置阿里云从默认内核启动

阿里云购买的第2块云盘默认是不自动挂载的,需要手动配置挂载上。 1.查看SSD云盘sudo fdisk -l可以看到SSD系统已经识别为/dev/vdb 2.格式化云盘sudo mkfs.ext4 /dev/vdb 点我领取阿里云2000元代金券,(阿里云优惠券的作用:购买阿里云产品,最后支付结算的时候,阿里云优惠券可抵扣一部分费用。3.挂载 sudo mount /dev/vdb /opt 将云盘挂载到/opt目录下。 4.配置开机自动挂载修改/etc/fstab文件,文件末尾添加:/dev/vdb /opt ext4 defaults 0 0 然后df -hl就可以看到第二块挂载成功咯! 阿里云服务器:活动地址 购买可领取:阿里云代金券

优秀的个人博客,低调大师

如何用source insight写内核代码

别的文章都会做很多说明, 铺垫, 我就不多说了, 直接来重点 vim写代码的时候, 有一种情况不是很好处理, 比如struct a{int x; int y; iny z}struct b{int x; int y; iny z} pb->z想从这里跳到到结构体b的定义需要编辑器理解pb的含义, 而不是简单的字符查找 那就让我们来用source insight吧 以前都是用Windows挂samba来运行的, 缺点就是速度慢, kernel code文件太多, 一共5w多个, 等同步要很久 还有人会把代码让到windows机器来看, 这样编辑, 编译都需要同步, 不方便 思路就是把source insight放到本地来跑, 用wine可以, 但是source insight是i386的, 所以需要32位的wine, 编译32位的wine

优秀的个人博客,低调大师

openGauss内核分析-统计信息与行数估计

目录 统计信息 行数估计 SQL引擎执行查询主要经历了词法语法解析、查询重写、查询规划和计划执行等步骤。其中,在查询规划过程中,为了生成可执行的最优计划,首先要生成路径,而由于路径存在多样性,因此需要对路径进行淘汰选择。目前优化器进行路径的选择主要是基于估算的代价,因此这种优化器也被称为基于代价的优化器(Cost Based Optimization,CBO)。相对于逻辑优化,这种优化方法是物理优化:根据数据的分布(统计信息)情况来对查询执行路径进行评估,从可选的路径中选择一个执行代价最小的路径进行执行,例如是否选择索引SeqScan vs. IndexScan,选择哪个索引,两表关联选择什么样的连接顺序,选择怎样的具体算法等。 在代价估算时,需要使用基表或连接表的行数,而在很多时候,优化器无法获得准确的行数值,因此需要对行数进行估算(Cardinality Estimation),然后再计算代价。 统计信息 统计信息是物理优化的依据,来源于表信息的统计。其中描述基表数据的特征包括唯一值、MCV(Most Common Value)值等,用于行数估算。 Table-Level表级别统计信息,存储在系统表pg_class。 relptuples总元组数:描述表对应的元组数。 relpages总页面数:描述表对应的磁盘页数。 Column-Level列级别统计信息,存储在系统表pg_statistics,也可以使用视图pg_stats查看数据。 Starelid:表的oid。 Staattnum:表属性编号。 stadistinct:用于描述字段里唯一的非 NULL 数据值的数目,一般用于估算集合分组之后的大小,Join结果集大小。 stanullfrac:用于描述当前列中NULL值在总数中的占比。 属性组{stakind1, stanumbers1, stavalues1}构成PG_STATISTIC表的一个卡槽,在PG_STATISTIC表中有5个卡槽。一般情况下,第一个卡槽存储MCV(Most Common Value)信息:描述出现频率大于一定百分比的值的集合,按照出现的频率进行排序,通常用于表征哪些值上出现了倾斜。第二个卡槽存储Histogram直方图信息,描述除了NULL值、MCV值以外的值的分布情况,一般用于估算选择率。 以MCV卡槽为例属性“stakind1”标识卡槽类型为MCV,其中“1”为“STATISTIC_KIND_MCV”的枚举值;属性stanumbers1与属性stavalues1记录MCV的具体内容,其中stavalues1记录key值,stanumbers1记录key对应的频次。 系统表pg_statistics的定义在文件pg_statistic.h中。 #define STATISTIC_KIND_MCV 1 #define STATISTIC_KIND_HISTOGRAM 2 #define STATISTIC_KIND_CORRELATION 3 #define STATISTIC_KIND_MCELEM 4 #define STATISTIC_KIND_DECHIST 5 统计信息通过analyze命令获得。 表tt的oid为40960,有10000行数据占用345个pages页。第1列unique1的分布情况可以从直方图信息获取,直方图有100个区间,并且没有空值和MCV。第16列string4的分布情况可以通过MCV信息获取,这一列有4个distinct值”AAAAxx” ,”HHHHxx” , “OOOOxx” , “VVVVxx” ,4个值的分布频次都有0.25。 行数估计 行数估算是代价估算的基础,来源于基表统计信息的推算,估算基表baserel、Join中间结果集joinrel、Aggregation中结果集大小,为代价估算做准备。 SQL查询常常带有where约束(过滤条件),比如SELECT * FROM tt WHERE string4 = 'AAAAxx'。知道了约束条件的选择率,也就是知道了通过扫描路径要扫描出来的结果所占的比例或者通过连接操作所获得的元组所占的比例,通过这个比例就可以推算出中间结果和最终结果的数量,进而使用这些数量来计算代价。 这里重点分析基表的简单查询——基于OpExpr类型的选择率计算,处理函数在clause_selectivity。如果是过滤条件就调用restriction_selectivity函数来获得OpExpr表达式的选择率,如果是连接条件则调用join_selectivity函数来获得选择率。 SELECT * FROM tt WHERE string4 = 'AAAAxx'为过滤条件,调用restriction_selectivity进行选择率估算。 restriction_selectivity函数识别出string4 = 'AAAAxx'是形如Var = Const的等值约束,操作符的约束选择性计算函数存储在系统表PG_OPERATOR,opno = 93对应的选择率计算函数为eqsel,通过eqsel函数调用var_eq_const函数进行选择率估算。在该过程中,var_eq_const函数会读取PG_STATISTIC表中string4列分布信息,并利用MCV信息直接返回选择率为0.25。 函数set_baserel_size_estimates计算估计行数。 函数调用关系:standard_planner-> subquery_planner-> grouping_planner-> query_planner-> make_one_rel-> set_base_rel_sizes-> set_rel_size-> set_plain_rel_size-> set_baserel_size_estimates-> clauselist_selectivity-> clause_selectivity-> restriction_selectivity-> OidFunctionCall4Coll-> eqsel->var_eq_const

优秀的个人博客,低调大师

从内核代码了解SQL如何解析

目录 词法分析Lexical Analysis 语法分析Syntax Analysis 语义分析Semantic Analysis 在传统数据库中SQL引擎一般指对用户输入的SQL语句进行解析、优化的软件模块。 SQL的解析过程主要分为: 词法分析Lexical Analysis:将用户输入的SQL语句拆解成单词(Token)序列,并识别出关键字、标识、常量等。 语法分析Syntax Analysis:分析器对词法分析器解析出来的单词(Token)序列在语法上是否满足SQL语法规则。 语义分析Semantic Analysis:语义分析是SQL解析过程的一个逻辑阶段,主要任务是在语法正确的基础上进行上下文有关性质的审查,在SQL解析过程中该阶段完成表名、操作符、类型等元素的合法性判断,同时检测语义上的二义性。 openGauss在pg_parse_query中调用raw_parser函数对用户输入的SQL命令进行词法分析和语法分析,生成语法树添加到链表parsetree_list中。完成语法分析后,对于parsetree_list中的每一颗语法树parsetree,会调用parse_analyze函数进行语义分析,根据SQL命令的不同,执行对应的入口函数,最终生成查询树。 词法分析Lexical Analysis openGauss使用flex工具进行词法分析。flex工具通过对已经定义好的词法文件进行编译,生成词法分析的代码。词法文件是scan.l,它根据SQL语言标准对SQL语言中的关键字、标识符、操作符、常量、终结符进行了定义和识别。在kwlist.h中定义了大量的关键字,按照字母的顺序排列,方便在查找关键字时通过二分法进行查找。在scan.l中处理“标识符”时,会到关键字列表中进行匹配,如果一个标识符匹配到关键字,则认为是关键字,否则才是标识符,即关键字优先. 以“select a, b from item”为例说明词法分析结果。 名称 词性 内容 说明 关键字 keyword SELECT,FROM 如SELECT/FROM/WHERE等,对大小写不敏感 标识符 IDENT a,b,item 用户自己定义的名字、常量名、变量名和过程名,若无括号修饰则对大小写不敏感 语法分析Syntax Analysis openGauss中定义了bison工具能够识别的语法文件gram.y,根据SQL语言的不同定义了一系列表达Statement的结构体(这些结构体通常以Stmt作为命名后缀),用来保存语法分析结果。以SELECT查询为例,它对应的Statement结构体如下。 typedef struct SelectStmt { NodeTag type; List *distinctClause; /* NULL, list of DISTINCT ON exprs, or * lcons(NIL,NIL) for all (SELECT DISTINCT) */ IntoClause *intoClause; /* target for SELECT INTO */ List *targetList; /* the target list (of ResTarget) */ List *fromClause; /* the FROM clause */ Node *whereClause; /* WHERE qualification */ List *groupClause; /* GROUP BY clauses */ Node *havingClause; /* HAVING conditional-expression */ List *windowClause; /* WINDOW window_name AS (...), ... */ WithClause *withClause; /* WITH clause */ List *valuesLists; /* untransformed list of expression lists */ List *sortClause; /* sort clause (a list of SortBy's) */ Node *limitOffset; /* # of result tuples to skip */ Node *limitCount; /* # of result tuples to return */ …… } SelectStmt; 这个结构体可以看作一个多叉树,每个叶子节点都表达了SELECT查询语句中的一个语法结构,对应到gram.y中,它会有一个SelectStmt。代码如下: 从simple_select语法分析结构可以看出,一条简单的查询语句由以下子句组成:去除行重复的distinctClause、目标属性targetList、SELECT INTO子句intoClause、FROM子句fromClause、WHERE子句whereClause、GROUP BY子句groupClause、HAVING子句havingClause、窗口子句windowClause和plan_hint子句。在成功匹配simple_select语法结构后,将会创建一个Statement结构体,将各个子句进行相应的赋值。对simple_select而言,目标属性、FROM子句、WHERE子句是最重要的组成部分。SelectStmt与其他结构体的关系如下: 下面以“select a, b from item”为例说明简单select语句的解析过程,函数exec_simple_query调用pg_parse_query执行解析,解析树中只有一个元素。 (gdb) p *parsetree_list $47 = {type = T_List, length = 1, head = 0x7f5ff986c8f0, tail = 0x7f5ff986c8f0} List中的节点类型为T_SelectStmt (gdb) p *(Node *)(parsetree_list->head.data->ptr_value) $45 = {type = T_SelectStmt} 查看SelectStmt结构体,targetList 和fromClause非空 (gdb) set $stmt = (SelectStmt *)(parsetree_list->head.data->ptr_value) (gdb) p *$stmt $50 = {type = T_SelectStmt, distinctClause = 0x0, intoClause = 0x0, targetList = 0x7f5ffa43d588, fromClause = 0x7f5ff986c888, startWithClause = 0x0, whereClause = 0x0, groupClause = 0x0, havingClause = 0x0, windowClause = 0x0, withClause = 0x0, valuesLists = 0x0, sortClause = 0x0, limitOffset = 0x0, limitCount = 0x0, lockingClause = 0x0, hintState = 0x0, op = SETOP_NONE, all = false, larg = 0x0, rarg = 0x0, hasPlus = false} 查看SelectStmt的targetlist,有两个ResTarget (gdb) p *($stmt->targetList) $55 = {type = T_List, length = 2, head = 0x7f5ffa43d540, tail = 0x7f5ffa43d800} (gdb) p *(Node *)($stmt->targetList->head.data->ptr_value) $57 = {type = T_ResTarget} (gdb) set $restarget1=(ResTarget *)($stmt->targetList->head.data->ptr_value) (gdb) p *$restarget1 $60 = {type = T_ResTarget, name = 0x0, indirection = 0x0, val = 0x7f5ffa43d378, location = 7} (gdb) p *$restarget1->val $63 = {type = T_ColumnRef} (gdb) p *(ColumnRef *)$restarget1->val $64 = {type = T_ColumnRef, fields = 0x7f5ffa43d470, prior = false, indnum = 0, location = 7} (gdb) p *((ColumnRef *)$restarget1->val)->fields $66 = {type = T_List, length = 1, head = 0x7f5ffa43d428, tail = 0x7f5ffa43d428} (gdb) p *(Node *)(((ColumnRef *)$restarget1->val)->fields)->head.data->ptr_value $67 = {type = T_String} (gdb) p *(Value *)(((ColumnRef *)$restarget1->val)->fields)->head.data->ptr_value $77 = {type = T_String, val = {ival = 140050197369648, str = 0x7f5ffa43d330 "a"}} (gdb) set $restarget2=(ResTarget *)($stmt->targetList->tail.data->ptr_value) (gdb) p *$restarget2 $89 = {type = T_ResTarget, name = 0x0, indirection = 0x0, val = 0x7f5ffa43d638, location = 10} (gdb) p *$restarget2->val $90 = {type = T_ColumnRef} (gdb) p *(ColumnRef *)$restarget2->val $91 = {type = T_ColumnRef, fields = 0x7f5ffa43d730, prior = false, indnum = 0, location = 10} (gdb) p *((ColumnRef *)$restarget2->val)->fields $92 = {type = T_List, length = 1, head = 0x7f5ffa43d6e8, tail = 0x7f5ffa43d6e8} (gdb) p *(Node *)(((ColumnRef *)$restarget2->val)->fields)->head.data->ptr_value $93 = {type = T_String} (gdb) p *(Value *)(((ColumnRef *)$restarget2->val)->fields)->head.data->ptr_value $94 = {type = T_String, val = {ival = 140050197370352, str = 0x7f5ffa43d5f0 "b"} 查看SelectStmt的fromClause,有一个RangeVar (gdb) p *$stmt->fromClause $102 = {type = T_List, length = 1, head = 0x7f5ffa43dfe0, tail = 0x7f5ffa43dfe0} (gdb) set $fromclause=(RangeVar*)($stmt->fromClause->head.data->ptr_value) (gdb) p *$fromclause $103 = {type = T_RangeVar, catalogname = 0x0, schemaname = 0x0, relname = 0x7f5ffa43d848 "item", partitionname = 0x0, subpartitionname = 0x0, inhOpt = INH_DEFAULT, relpersistence = 112 'p', alias = 0x0, location = 17, ispartition = false, issubpartition = false, partitionKeyValuesList = 0x0, isbucket = false, buckets = 0x0, length = 0, foreignOid = 0, withVerExpr = false} 综合以上分析可以得到语法树结构 语义分析Semantic Analysis 在完成词法分析和语法分析后,parse_analyze函数会根据语法树的类型,调用transformSelectStmt将parseTree改写为查询树。 (gdb) p *result $3 = {type = T_Query, commandType = CMD_SELECT, querySource = QSRC_ORIGINAL, queryId = 0, canSetTag = false, utilityStmt = 0x0, resultRelation = 0, hasAggs = false, hasWindowFuncs = false, hasSubLinks = false, hasDistinctOn = false, hasRecursive = false, hasModifyingCTE = false, hasForUpdate = false, hasRowSecurity = false, hasSynonyms = false, cteList = 0x0, rtable = 0x7f5ff5eb8c88, jointree = 0x7f5ff5eb9310, targetList = 0x7f5ff5eb9110,…} (gdb) p *result->targetList $13 = {type = T_List, length = 2, head = 0x7f5ff5eb90c8, tail = 0x7f5ff5eb92c8} (gdb) p *(Node *)(result->targetList->head.data->ptr_value) $8 = {type = T_TargetEntry} (gdb) p *(TargetEntry*)(result->targetList->head.data->ptr_value) $9 = {xpr = {type = T_TargetEntry, selec = 0}, expr = 0x7f5ff636ff48, resno = 1, resname = 0x7f5ff5caf330 "a", ressortgroupref = 0, resorigtbl = 24576, resorigcol = 1, resjunk = false} (gdb) p *(TargetEntry*)(result->targetList->tail.data->ptr_value) $10 = {xpr = {type = T_TargetEntry, selec = 0}, expr = 0x7f5ff5eb9178, resno = 2, resname = 0x7f5ff5caf5f0 "b", ressortgroupref = 0, resorigtbl = 24576, resorigcol = 2, resjunk = false} (gdb) (gdb) p *result->rtable $14 = {type = T_List, length = 1, head = 0x7f5ff5eb8c40, tail = 0x7f5ff5eb8c40} (gdb) p *(Node *)(result->rtable->head.data->ptr_value) $15 = {type = T_RangeTblEntry} (gdb) p *(RangeTblEntry*)(result->rtable->head.data->ptr_value) $16 = {type = T_RangeTblEntry, rtekind = RTE_RELATION, relname = 0x7f5ff636efb0 "item", partAttrNum = 0x0, relid = 24576, partitionOid = 0, isContainPartition = false, subpartitionOid = 0……} 得到的查询树结构如下: 完成词法、语法和语义分析后,SQL解析过程完成,SQL引擎开始执行查询优化。

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册