解析SQL执行过程
sql的执行流程
sql的执行流程SQL的执行过程是指将SQL语句转换成实际操作数据库的过程。
SQL语言是一种高级语言,虽然简单易懂,但是实际执行时却需要经过多方面的处理。
1. 词法分析SQL语句首先要经过词法分析,将SQL语句中的每个单词、符号等进行在此阶段进行识别、分类、拆解,变成一个个独立的语言成分。
这个处理过程被称为标记化。
其实就是将SQL语句逐个字符逐个字符组合起来,形成不同的单词。
对于不同的单词采取不同的处理方式。
例如,对于SELECT语句,要分解为SELECT、*、FROM、table等单词。
将经过词法分析的结果进行语法分析。
语法分析依赖于事先定义的语法规则,将标记化后的字符序列转化成一棵语法树,使得语句的结构和语义被更准确地表达出来,同时将错误和矛盾进行识别和处理。
3. 语义解析对SQL执行的第三个阶段是语义解析。
语义解析是指对SQL语句的具体含义进行解释,包括表名、字段名、类型、长度、函数等信息的解析,从信息部分进行转换。
4. 优化阶段在不改变SQL语句结果的前提下,通过改变多种执行计划的方式来确定最佳的执行计划,从而让SQL语句的执行效率更高,避免了浪费资源的情况。
在这个阶段,会考虑如何避免表的重复扫描、如何利用索引等问题。
5. 执行阶段经过词法分析、语法分析、语义解析和优化的SQL语句将被执行。
执行SQL语句需要数据库系统从磁盘读取数据、进行表Join、对数据进行Group By、对数据进行排序等等,执行过程complex,也是一串复杂流程的集合。
6. 结果处理阶段经过以上步骤,若顺利完成,那么接下来的步骤就是将执行完毕的结果处理并将其返回给用户。
用户得到返回的数据后,再进行后续的处理。
总的说来,SQL的执行流程非常复杂,需要经过多个步骤的处理来实现。
不过,每个步骤都有它的独特作用和功能,其中的每一步都是必不可少的。
【原创】大数据基础之Hive(2)HiveSQL执行过程之SQL解析过程
【原创】⼤数据基础之Hive(2)HiveSQL执⾏过程之SQL解析过程Hive SQL解析过程SQL->AST(Abstract Syntax Tree)->Task(MapRedTask,FetchTask)->QueryPlan(Task集合)->Job(Yarn)SQL解析会在两个地⽅进⾏:⼀个是SQL执⾏前compile,具体在pile,为了创建QueryPlan;⼀个是explain,具体在ExplainSemanticAnalyzer.analyzeInternal,为了创建ExplainTask;SQL执⾏过程1 compile过程(SQL->AST(Abstract Syntax Tree)->QueryPlan)org.apache.hadoop.hive.ql.Driverpublic int compile(String command, boolean resetTaskIds, boolean deferClose) {...ParseDriver pd = new ParseDriver();ASTNode tree = pd.parse(command, ctx);tree = ParseUtils.findRootNonNullToken(tree);...BaseSemanticAnalyzer sem = SemanticAnalyzerFactory.get(queryState, tree);...sem.analyze(tree, ctx);...// Record any ACID compliant FileSinkOperators we saw so we can add our transaction ID to// them later.acidSinks = sem.getAcidFileSinks();("Semantic Analysis Completed");// validate the plansem.validate();acidInQuery = sem.hasAcidInQuery();perfLogger.PerfLogEnd(CLASS_NAME, PerfLogger.ANALYZE);if (isInterrupted()) {return handleInterruption("after analyzing query.");}// get the output schemaschema = getSchema(sem, conf);plan = new QueryPlan(queryStr, sem, perfLogger.getStartTime(PerfLogger.DRIVER_RUN), queryId,queryState.getHiveOperation(), schema);...compile过程为先由ParseDriver将SQL转换为ASTNode,然后由BaseSemanticAnalyzer对ASTNode进⾏分析,最后将BaseSemanticAnalyzer传⼊QueryPlan构造函数来创建QueryPlan;1)将SQL转换为ASTNode过程如下(SQL->AST(Abstract Syntax Tree))org.apache.hadoop.hive.ql.parse.ParseDriverpublic ASTNode parse(String command, Context ctx, boolean setTokenRewriteStream)throws ParseException {if (LOG.isDebugEnabled()) {LOG.debug("Parsing command: " + command);}HiveLexerX lexer = new HiveLexerX(new ANTLRNoCaseStringStream(command));TokenRewriteStream tokens = new TokenRewriteStream(lexer);if (ctx != null) {if ( setTokenRewriteStream) {ctx.setTokenRewriteStream(tokens);}lexer.setHiveConf(ctx.getConf());}HiveParser parser = new HiveParser(tokens);if (ctx != null) {parser.setHiveConf(ctx.getConf());}parser.setTreeAdaptor(adaptor);HiveParser.statement_return r = null;try {r = parser.statement();} catch (RecognitionException e) {e.printStackTrace();throw new ParseException(parser.errors);}if (lexer.getErrors().size() == 0 && parser.errors.size() == 0) {LOG.debug("Parse Completed");} else if (lexer.getErrors().size() != 0) {throw new ParseException(lexer.getErrors());} else {throw new ParseException(parser.errors);}ASTNode tree = (ASTNode) r.getTree();tree.setUnknownTokenBoundaries();return tree;}2)analyze过程(AST(Abstract Syntax Tree)->Task)org.apache.hadoop.hive.ql.parse.BaseSemanticAnalyzerpublic void analyze(ASTNode ast, Context ctx) throws SemanticException {initCtx(ctx);init(true);analyzeInternal(ast);}其中analyzeInternal是抽象⽅法,由不同的⼦类实现,⽐如DDLSemanticAnalyzer,SemanticAnalyzer,UpdateDeleteSemanticAnalyzer,ExplainSemanticAnalyzer等;analyzeInternal主要的⼯作是将ASTNode转化为Task,包括可能的optimize,过程⽐较复杂,这⾥不贴代码;3)创建QueryPlan过程如下(Task->QueryPlan)org.apache.hadoop.hive.ql.QueryPlanpublic QueryPlan(String queryString, BaseSemanticAnalyzer sem, Long startTime, String queryId,HiveOperation operation, Schema resultSchema) {this.queryString = queryString;rootTasks = new ArrayList<Task<? extends Serializable>>(sem.getAllRootTasks());reducerTimeStatsPerJobList = new ArrayList<ReducerTimeStatsPerJob>();fetchTask = sem.getFetchTask();// Note that inputs and outputs can be changed when the query gets executedinputs = sem.getAllInputs();outputs = sem.getAllOutputs();linfo = sem.getLineageInfo();tableAccessInfo = sem.getTableAccessInfo();columnAccessInfo = sem.getColumnAccessInfo();idToTableNameMap = new HashMap<String, String>(sem.getIdToTableNameMap());this.queryId = queryId == null ? makeQueryId() : queryId;query = new org.apache.hadoop.hive.ql.plan.api.Query();query.setQueryId(this.queryId);query.putToQueryAttributes("queryString", this.queryString);queryProperties = sem.getQueryProperties();queryStartTime = startTime;this.operation = operation;this.autoCommitValue = sem.getAutoCommitValue();this.resultSchema = resultSchema;}可见只是简单的将BaseSemanticAnalyzer中的内容拷贝出来,其中最重要的是sem.getAllRootTasks和sem.getFetchTask;2 execute过程(QueryPlan->Job)org.apache.hadoop.hive.ql.Driverpublic int execute(boolean deferClose) throws CommandNeedRetryException {...// Add root Tasks to runnablefor (Task<? extends Serializable> tsk : plan.getRootTasks()) {// This should never happen, if it does, it's a bug with the potential to produce// incorrect results.assert tsk.getParentTasks() == null || tsk.getParentTasks().isEmpty();driverCxt.addToRunnable(tsk);...// Loop while you either have tasks running, or tasks queued upwhile (driverCxt.isRunning()) {// Launch upto maxthreads tasksTask<? extends Serializable> task;while ((task = driverCxt.getRunnable(maxthreads)) != null) {TaskRunner runner = launchTask(task, queryId, noName, jobname, jobs, driverCxt);if (!runner.isRunning()) {break;}}...private TaskRunner launchTask(Task<? extends Serializable> tsk, String queryId, boolean noName,String jobname, int jobs, DriverContext cxt) throws HiveException {...TaskRunner tskRun = new TaskRunner(tsk, tskRes);...tskRun.start();...tskRun.runSequential();...Driver.run中从QueryPlan中取出Task,并逐个launchTask,launchTask过程为将Task包装为TaskRunner,并最终调⽤TaskRunner.runSequential,下⾯看TaskRunner:org.apache.hadoop.hive.ql.exec.TaskRunnerpublic void runSequential() {int exitVal = -101;try {exitVal = tsk.executeTask();...这⾥直接调⽤Task.executeTaskorg.apache.hadoop.hive.ql.exec.Taskpublic int executeTask() {...int retval = execute(driverContext);...这⾥execute是抽象⽅法,由⼦类实现,⽐如DDLTask,MapRedTask等,着重看MapRedTask,因为⼤部分的Task都是MapRedTask:org.apache.hadoop.hive.ql.exec.mr.MapRedTaskpublic int execute(DriverContext driverContext) {...if (!runningViaChild) {// we are not running this mapred task via child jvm// so directly invoke ExecDriverreturn super.execute(driverContext);}...这⾥直接调⽤⽗类⽅法,也就是ExecDriver.execute,下⾯看:org.apache.hadoop.hive.ql.exec.mr.ExecDriverprotected transient JobConf job;...public int execute(DriverContext driverContext) {...JobClient jc = null;MapWork mWork = work.getMapWork();ReduceWork rWork = work.getReduceWork();...if (mWork.getNumMapTasks() != null) {job.setNumMapTasks(mWork.getNumMapTasks().intValue());}...job.setNumReduceTasks(rWork != null ? rWork.getNumReduceTasks().intValue() : 0);job.setReducerClass(ExecReducer.class);...jc = new JobClient(job);...rj = jc.submitJob(job);this.jobID = rj.getJobID();这⾥将Task转化为Job提交到Yarn执⾏;SQL Explain过程另外⼀个SQL解析的过程是explain,在ExplainSemanticAnalyzer中将ASTNode转化为ExplainTask:org.apache.hadoop.hive.ql.parse.ExplainSemanticAnalyzerpublic void analyzeInternal(ASTNode ast) throws SemanticException {...ctx.setExplain(true);ctx.setExplainLogical(logical);// Create a semantic analyzer for the queryASTNode input = (ASTNode) ast.getChild(0);BaseSemanticAnalyzer sem = SemanticAnalyzerFactory.get(queryState, input);sem.analyze(input, ctx);sem.validate();ctx.setResFile(ctx.getLocalTmpPath());List<Task<? extends Serializable>> tasks = sem.getAllRootTasks();if (tasks == null) {tasks = Collections.emptyList();}FetchTask fetchTask = sem.getFetchTask();if (fetchTask != null) {// Initialize fetch work such that operator tree will be constructed.fetchTask.getWork().initializeForFetch(ctx.getOpContext());}ParseContext pCtx = null;if (sem instanceof SemanticAnalyzer) {pCtx = ((SemanticAnalyzer)sem).getParseContext();}boolean userLevelExplain = !extended&& !formatted&& !dependency&& !logical&& !authorize&& (HiveConf.getBoolVar(ctx.getConf(), HiveConf.ConfVars.HIVE_EXPLAIN_USER) && HiveConf.getVar(conf, HiveConf.ConfVars.HIVE_EXECUTION_ENGINE).equals("tez"));ExplainWork work = new ExplainWork(ctx.getResFile(),pCtx,tasks,fetchTask,sem,extended,formatted,dependency,logical,authorize,userLevelExplain,ctx.getCboInfo());work.setAppendTaskType(HiveConf.getBoolVar(conf, HiveConf.ConfVars.HIVEEXPLAINDEPENDENCYAPPENDTASKTYPES));ExplainTask explTask = (ExplainTask) TaskFactory.get(work, conf);fieldList = explTask.getResultSchema();rootTasks.add(explTask);}。
sql语句的执行过程
sql语句的执行过程
SQL语句的执行过程主要包括以下几个步骤:
1.语法分析:数据库系统会对输入的SQL语句进行语法分析,检查语句是否符合SQL语法规范,如果语法有误则会抛出错误信息。
2.语义分析:在语法分析的基础上,数据库系统会对语句进行语义分析,检查语句中的表、列、数据类型等是否存在或合法。
3.查询优化:对于查询语句,数据库系统会根据表的结构和索引等信息,通过优化器对查询进行优化,找到最优的执行计划。
4.访问数据库:根据查询语句的执行计划,数据库系统会访问数据库中的数据,读取或修改相应的表和行。
5.数据返回:查询语句执行完成后,数据库系统会将结果返回给应用程序或客户端。
如果是DML语句(如INSERT、UPDATE、DELETE),则返回被影响的行数。
6.事务处理:在执行过程中,数据库系统会根据事务的隔离级别和事务控制语句(如BEGIN、COMMIT、ROLLBACK)来进行事务处理,保证数据的一致性和完整性。
注:以上是一般情况下的SQL语句执行过程,不同的数据库系统可能会有一些差异,具体执行过程可能会有所变化。
SQL语句的执行原理分析及where 查询条件决定SQL效率
SQL语句的执行原理分析及where 查询条件决定SQL效率原理:第一步:应用程序把查询SQL语句发给服务器端执行。
我们在数据层执行SQL语句时,应用程序会连接到相应的数据库服务器,把SQL语句发送给服务器处理。
第二步:服务器解析请求的SQL语句。
1:SQL计划缓存,经常用查询分析器的朋友大概都知道这样一个事实,往往一个查询语句在第一次运行的时候需要执行特别长的时间,但是如果你马上或者在一定时间内运行同样的语句,会在很短的时间内返回查询结果。
原因:1):服务器在接收到查询请求后,并不会马上去数据库查询,而是在数据库中的计划缓存中找是否有相对应的执行计划,如果存在,就直接调用已经编译好的执行计划,节省了执行计划的编译时间。
2):如果所查询的行已经存在于数据缓冲存储区中,就不用查询物理文件了,而是从缓存中取数据,这样从内存中取数据就会比从硬盘上读取数据快很多,提高了查询效率.数据缓冲存储区会在后面提到。
2:如果在SQL计划缓存中没有对应的执行计划,服务器首先会对用户请求的SQL语句进行语法效验,如果有语法错误,服务器会结束查询操作,并用返回相应的错误信息给调用它的应用程序。
注意:此时返回的错误信息中,只会包含基本的语法错误信息,例如select 写成selec等,错误信息中如果包含一列表中本没有的列,此时服务器是不会检查出来的,因为只是语法验证,语义是否正确放在下一步进行。
3:语法符合后,就开始验证它的语义是否正确,例如,表名,列名,存储过程等等数据库对象是否真正存在,如果发现有不存在的,就会报错给应用程序,同时结束查询。
4:接下来就是获得对象的解析锁,我们在查询一个表时,首先服务器会对这个对象加锁,这是为了保证数据的统一性,如果不加锁,此时有数据插入,但因为没有加锁的原因,查询已经将这条记录读入,而有的插入会因为事务的失败会回滚,就会形成脏读的现象。
5:接下来就是对数据库用户权限的验证,SQL语句语法,语义都正确,此时并不一定能够得到查询结果,如果数据库用户没有相应的访问权限,服务器会报出权限不足的错误给应用程序,在稍大的项目中,往往一个项目里面会包含好几个数据库连接串,这些数据库用户具有不同的权限,有的是只读权限,有的是只写权限,有的是可读可写,根据不同的操作选取不同的用户来执行,稍微不注意,无论你的SQL语句写的多么完善,完美无缺都没用。
flink sql执行流程
flink sql执行流程Flink SQL执行流程是指Flink在处理SQL查询时的具体执行过程。
下面以Flink 1.12版本为例,详细描述了Flink SQL的执行流程。
1. 解析SQL语句:Flink SQL首先会对输入的SQL语句进行解析,将其转换为逻辑执行计划。
解析过程包括词法分析、语法分析和语义分析。
词法分析将输入的SQL语句分解为一个个的token;语法分析将tokens序列转换为抽象语法树(AST);语义分析将AST转换为逻辑执行计划。
2. 优化执行计划:Flink SQL会对生成的逻辑执行计划进行优化,包括逻辑优化和物理优化。
逻辑优化主要考虑查询的语义等价转换和逻辑规则的应用,以提高查询性能;物理优化主要考虑查询的物理执行计划生成,包括选择合适的物理算子、优化数据传输等。
3. 生成任务图:优化后的执行计划将转换为任务图,任务图是Flink作业的执行图形表示,用于描述作业的数据依赖关系以及任务之间的执行关系。
任务图由一系列的模块(源任务、转换任务、汇任务)和边(数据通道)组成。
4. 提交作业:生成的任务图将被提交到Flink的作业管理器。
作业管理器根据任务图生成作业提交请求,并将作业提交给资源管理器。
资源管理器根据可用资源的情况进行资源调度,分配任务给TaskManager。
5. 执行作业:TaskManager接收到作业后,会根据任务图中的任务进行执行。
每个TaskManager都根据任务图中的任务在本地执行相应的计算任务,计算结果可以存储在内存中或者持久化到外部系统中。
6. 并发处理:Flink支持作业的并发执行,多个TaskManager可以同时执行不同任务,以实现并行计算。
在并行计算中,TaskManager之间可以通过网络进行数据传输和交换。
数据会根据任务图中的数据通道进行传输,以满足任务间的数据依赖关系。
7. 结果输出:Flink任务执行完后,可以根据需要将计算结果输出。
mysql 中的 sql执行流程
mysql 中的 sql执行流程Mysql 中的 SQL 执行流程概述•MySQL 是一款广泛使用的开源关系型数据库管理系统,它使用SQL 语言进行数据管理和操作。
•SQL 执行流程是指 MySQL 在执行 SQL 语句时的内部运行过程,包括解析 SQL 语句、优化执行计划、执行计划等多个步骤。
SQL 执行流程步骤1.解析 SQL 语句–MySQL 首先会对输入的 SQL 语句进行解析,判断语法的正确性和合法性。
–解析过程包括词法分析和语法分析,将 SQL 语句转换成抽象语法树(AST)表示。
2.语义分析–在语义分析阶段,MySQL 对解析得到的抽象语法树进行分析,并验证 SQL 语句是否符合语义规则。
–语义分析会检查表名、列名的存在性、权限等,并进行相应的错误提示或警告。
3.优化执行计划–在优化执行计划阶段,MySQL 会根据 SQL 语句的查询需求和数据库的特点,生成多个执行计划。
–MySQL 内部会使用优化器选择出最优的执行计划,以提高查询效率。
–优化过程包括索引选择、连接顺序优化、子查询优化等。
4.执行计划–在执行计划阶段,MySQL 会根据最优的执行计划,按照特定的流程执行 SQL 语句。
–MySQL 会使用存储引擎的接口,读取和写入数据。
存储引擎的作用•存储引擎是 MySQL 中负责底层数据存储和管理的模块,不同的存储引擎有不同的特点和适用场景。
•MySQL 支持多种存储引擎,如 InnoDB、MyISAM、Memory 等。
InnoDB 存储引擎•InnoDB 是 MySQL 中最常用和性能较好的存储引擎。
•InnoDB 支持事务和行级锁,具有高并发性和数据一致性。
MyISAM 存储引擎•MyISAM 是 MySQL 的另一个常用的存储引擎。
•MyISAM 不支持事务,但在读写比较均衡的场景下,有较好的性能。
Memory 存储引擎•Memory 存储引擎将数据存储在内存中,适用于一些读写频繁但数据不需要长期存储的场景。
ORACLESQL语句执行流程与顺序原理解析
ORACLESQL语句执行流程与顺序原理解析在ORACLESQL中,执行一个SQL语句的流程和顺序如下:1.语法分析:首先,ORACLE会对SQL语句进行语法分析,检查语法的正确性和完整性。
如果SQL语句存在语法错误,ORACLE会报错并中止执行。
2.词法分析:在语法分析之后,ORACLE会对SQL语句进行词法分析,将语句分解为最小的语义单元,如关键字、表名、列名等。
这些语义单元被存储在内部数据结构中,以供后续处理使用。
3.查询优化:在语法和词法分析之后,ORACLE会进行查询优化,以确定最佳的执行计划。
查询优化是一个复杂的过程,其中包括确定表的访问顺序、连接顺序、选择合适的索引等。
ORACLE会根据统计信息和系统设置来评估每个可能的执行计划,并选择成本最低的执行计划作为最终的执行方案。
4.查询执行:一旦确定了最佳的执行计划,ORACLE就开始执行SQL查询。
查询执行过程通常包括以下步骤:a.打开表:根据执行计划,ORACLE会按照指定的顺序打开需要查询的表。
b.获取数据:ORACLE会根据执行计划从打开的表中获取需要的数据。
这个过程包括索引的查找、数据块的读取等。
c.执行操作:一旦获取到数据,ORACLE会执行SQL语句中指定的操作,如查询、插入、更新等。
这些操作会在内存中进行,直到事务提交或回滚。
d.关闭表:当查询完成后,ORACLE会关闭查询过程中打开的表,释放相关的资源。
5.结果返回:最后,ORACLE将查询的结果返回给客户端。
这些结果可以是查询结果集、插入、更新的行数等。
总结起来,ORACLESQL语句的执行流程可以简单概括为语法分析、词法分析、查询优化、查询执行和结果返回。
这个过程确保了SQL语句的正确性和效率。
1条sql执行的完整过程
1条sql执行的完整过程当一条SQL语句被提交给数据库执行时,它需要经过多个步骤才能完成。
以下是SQL语句执行的完整过程:1. **解析(Parsing)**:* 查询首先被解析器解析。
解析器检查SQL语句的语法和结构,并创建一个解析树。
* 语法错误在这个阶段会被检测出来。
2. **预处理(Preprocessing)**:* 在预处理器中,解析器检查是否有任何语法错误,并确保所有的对象(如表和视图)都存在并且可以访问。
* 预处理器还会处理一些简单的查询重写,例如处理别名和子查询。
3. **优化(Optimization)**:* 在这个阶段,查询优化器会生成多个可能的执行计划,并选择一个最优的计划来执行查询。
* 优化器会考虑多种因素,如表的大小、索引的存在与否、数据的分布等,来决定最佳的执行策略。
4. **生成执行计划(Plan Generation)**:* 一旦选择了最优的执行计划,就会生成一个或多个执行计划。
这些计划描述了数据库如何实际执行查询。
5. **执行(Execution)**:* 在这个阶段,数据库引擎根据执行计划执行查询。
这可能涉及到读取数据、连接表、过滤记录等操作。
6. **返回结果(Result Returning)**:* 最后,查询的结果被返回给客户端。
这可能是一个表、一行数据、一个状态码等,具体取决于查询的类型和需求。
7. **后处理(Postprocessing)**:* 在某些情况下,可能还需要进行一些后处理步骤,例如处理事务或清理资源。
注意:不同的数据库系统可能会有不同的执行步骤或略有不同的执行顺序。
上述过程是一个通用的概述。
详细分析SQL语句逻辑执行过程和相关语法
详细分析SQL语句逻辑执⾏过程和相关语法1.1 SQL语句的逻辑处理顺序SQL语句的逻辑处理顺序,指的是SQL语句按照⼀定的规则,⼀整条语句应该如何执⾏,每⼀个关键字、⼦句部分在什么时刻执⾏。
除了逻辑顺序,还有物理执⾏顺序。
物理顺序是SQL语句真正被执⾏时的顺序(执⾏计划),它是由各数据库系统的关系引擎中的语句分析器、优化器等等组件经过⼤量计算、分析决定的。
很多时候因为优化的关系,使得语句最终的物理执⾏顺序和逻辑顺序不同。
按照逻辑顺序,有些应该先执⾏的过程,可能优化器会指定它后执⾏。
但不管是逻辑顺序还是物理顺序,设计了⼀条SQL语句,语句最后返回的结果不会也不能因为物理顺序改变了逻辑顺序⽽改变。
其实,逻辑顺序只是为我们编写、理解SQL语句提供些帮助,除此之外,它毫⽆⽤处。
⽽且,是不是真的存在⼀条严格且完整的执⾏顺序规则都是不确定的事情。
虽然某些书上、⽹上给出了⼀些顺序(我个⼈所知道的⽐较权威的,是SQL Server的"圣书"技术内幕⾥介绍过),但在任何⼀种数据库系统的官⽅⼿册上都没有关于这⽅⾯的介绍⽂档。
SQL Server和Oracle在语句的逻辑处理顺序上是⼀致的,在这⽅⾯,它们严格遵守了标准SQL的要求,任何⼀个步骤都遵循了关系型数据库的范式要求。
因为遵循了⼀些范式要求,导致标准SQL不允许使⽤某些语法。
但是MySQL、MariaDB和它们⼩有不同,它们对标准SQL进⾏扩展,标准SQL中不允许使⽤的语法,在MySQL、MariaDB中可能可以使⽤,但很多时候这会违反关系模型的范式要求。
虽然本⽂的最初⽬的是介绍MariaDB/MySQL语句的逻辑处理顺序,但在篇幅上对标准SQL介绍的更多,因为它们符合规范。
理解这些规范,实际上是在理解关系模型和集合模型。
本⽂也在多处通过这两个模型来分析为什么标准SQL不允许某些语法,以及为什么MySQL可以⽀持这些"不标准"的语法。
sql查询的执行流程
sql查询的执行流程SQL查询的执行流程SQL(Structured Query Language)是用于管理和操作关系数据库的标准语言。
在实际的数据库操作中,查询是最常用的操作之一。
SQL查询的执行流程包括以下几个步骤:解析、编译、优化、执行和返回结果。
1. 解析在执行SQL查询之前,数据库管理系统(DBMS)首先需要对查询语句进行解析。
解析的目的是将查询语句分解为语法分析树或解析树,以便后续的处理。
解析器会检查查询语句的语法是否正确,并将其转换为内部的数据结构。
如果查询语句存在语法错误,解析器会返回相应的错误信息。
2. 编译在解析完成后,DBMS会将解析树转换为可执行的代码。
这个过程被称为编译。
编译器会将解析树转换为DBMS内部的中间表示形式,这种形式通常是一种虚拟机指令或类似于机器码的形式。
编译器会对查询进行语义分析,并生成一个执行计划。
执行计划描述了如何从数据库中获取所需的数据以及如何执行其他操作,如连接、排序和聚合。
3. 优化在生成执行计划后,DBMS会对执行计划进行优化。
优化器会尝试找到最佳的执行计划,以便在最短的时间内返回正确的结果。
优化的过程包括选择合适的索引、调整连接顺序、重新排序操作等。
优化器会考虑查询的各种因素,如表的大小、索引的选择性、统计信息等,以确定最佳的执行路径。
4. 执行在优化完成后,DBMS会执行生成的执行计划。
执行器会按照执行计划的指令逐步执行,从数据库中获取所需的数据,并进行相应的操作。
执行的过程包括访问磁盘、读取数据、进行计算和过滤等。
执行器会按照指定的顺序依次执行查询中的各个操作,并将结果保存在临时表或内存中。
5. 返回结果在执行完成后,DBMS会将查询的结果返回给用户。
结果可以是一个数据集,也可以是一个标量值。
用户可以通过应用程序或命令行界面获取查询的结果。
返回的结果可能需要经过进一步的处理和格式化,以便于用户的查看和分析。
总结SQL查询的执行流程包括解析、编译、优化、执行和返回结果这几个关键步骤。
hive的sql执行流程
hive的sql执行流程
Hive的SQL执行流程大致可以分为以下几个步骤:
1. SQL解析与编译:Hive首先将输入的SQL查询语句进行解析,将其转化为抽象语法树(AST)。
然后,这个AST会被转换成逻辑执行计划。
在编译阶段,Hive会进行一些优化,比如重新排序操作,以改进查询的效率。
2. 元数据访问:在编译阶段,Hive会访问元数据(metadata)来获取表的结构、列的数据类型等信息。
这些信息对于后续的查询优化和执行非常重要。
3. 生成物理执行计划:基于逻辑执行计划和元数据信息,Hive会生成物理
执行计划。
物理执行计划包含了如何实际执行查询的具体步骤,例如数据的加载、过滤、连接等操作。
4. 执行物理计划:物理执行计划被提交给执行引擎来执行。
这个阶段包括数据加载、过滤、排序、连接等操作,这些操作可能会涉及到Hive的不同组件,比如Hive Metastore、HiveServer2等。
5. 结果输出:查询完成后,结果会被返回给客户端。
如果查询是SELECT类型的,结果会被返回给客户端;如果查询是INSERT类型的,结果会被写入到HDFS或者其他存储系统中。
6. 清理:最后,Hive会进行一些清理工作,比如释放资源、清理临时文件等。
以上就是Hive的SQL执行流程。
需要注意的是,这个流程可能会因为Hive的不同版本或者配置有所不同。
SQL语句执行过程详解
SQL语句执⾏过程详解 ⼀、SQL语句执⾏原第⼀步:客户端把语句发给服务器端执⾏当我们在客户端执⾏ select 语句时,客户端会把这条 SQL 语句发送给服务器端,让服务器端的进程来处理这语句。
也就是说,Oracle 客户端是不会做任何的操作,他的主要任务就是把客户端产⽣的⼀些 SQL 语句发送给服务器端。
虽然在客户端也有⼀个数据库进程,但是,这个进程的作⽤跟服务器上的进程作⽤事不相同的。
服务器上的数据库进程才会对SQL 语句进⾏相关的处理。
不过,有个问题需要说明,就是客户端的进程跟服务器的进程是⼀⼀对应的。
也就是说,在客户端连接上服务器后,在客户端与服务器端都会形成⼀个进程,客户端上的我们叫做客户端进程;⽽服务器上的我们叫做服务器进程。
第⼆步:语句解析当客户端把 SQL 语句传送到服务器后,服务器进程会对该语句进⾏解析。
同理,这个解析的⼯作,也是在服务器端所进⾏的。
虽然这只是⼀个解析的动作,但是,其会做很多“⼩动作”。
1. 查询⾼速缓存(library cache)。
服务器进程在接到客户端传送过来的 SQL 语句时,不会直接去数据库查询。
⽽是会先在数据库的⾼速缓存中去查找,是否存在相同语句的执⾏计划。
如果在数据⾼速缓存中,则服务器进程就会直接执⾏这个 SQL 语句,省去后续的⼯作。
所以,采⽤⾼速数据缓存的话,可以提⾼ SQL 语句的查询效率。
⼀⽅⾯是从内存中读取数据要⽐从硬盘中的数据⽂件中读取数据效率要⾼,另⼀⽅⾯,也是因为这个语句解析的原因。
不过这⾥要注意⼀点,这个数据缓存跟有些客户端软件的数据缓存是两码事。
有些客户端软件为了提⾼查询效率,会在应⽤软件的客户端设置数据缓存。
由于这些数据缓存的存在,可以提⾼客户端应⽤软件的查询效率。
但是,若其他⼈在服务器进⾏了相关的修改,由于应⽤软件数据缓存的存在,导致修改的数据不能及时反映到客户端上。
从这也可以看出,应⽤软件的数据缓存跟数据库服务器的⾼速数据缓存不是⼀码事。
sql执行过程
§ 1.4.1 SQL语句处理顺序SQL 语句处理分两个或三个阶段,每个语句从用户进程传给服务器进程进行分析然后执行。
如果是select 语句,则还需要将结果返回给用户。
1.分析(Parse)2929分析是SQL语句处理的第一步。
主要进行:l 检查语法和根据字典来检查表名、列名。
l 确定用户执行语句的权限。
l 为语句确定最优的执行计划。
l 从SQL 区中找出语句。
2.执行(Execute)Oracle 执行阶段执行的是被分析过的语句。
对于UPDATE、DELETE 语句,Oracle 先锁住有关的行。
Oracle 还要查找数据是否在数据缓冲区里。
如果不在还得从数据文件中将数据读到数据缓冲区里来。
3.检索(Fetch )如果是select 语句,还要进行检索操作。
执行结束,将数据返回给用户。
4.Select 语句处理:一般select 语句处理要经过下面步骤:执行顺序是:1)建立光标。
2)分析语句。
3)定义输出:指定位置,类型,结果集的数据类型。
4)绑定变量:如果查询使用变量的话,Oracle 就要知道变量的值。
5)是否能并行运行。
6)执行查询。
7)检索出数据。
8)关闭光标。
5.DML 语句处理:一般INSERT,UPADTE,DELETE 语句处理要经过下面步骤:执行顺序是:1)建立光标:Oracle建立一个隐含的光标。
2)分析语句。
3)绑定变量:如果语句用了变量,Oracle 要知道变量的值。
4)看语句是否能以并行方式运行(如果有多个服务器时)。
5)执行语句。
6)通知用户,语句已执行完毕。
7)关闭光标。
§ 1.4.2 COMMIT语句处理顺序当事务提交时,Oracle 分配一个唯一的顺序号SCN(System Change Number)给事务。
数据库恢复总是基于该SCN 号来进行处理。
SCN 号是记录在控制文件、数据文件、块头及重做日志文件中。
1.COMMIT处理步骤:Oracle 在下面情况提交事务:l 发出一个COMMIT语句。
数据库SQL语句的执行顺序及每一步的详细解释
数据库SQL语句的执行顺序及每一步的详细解释SQL语句的执行顺序如下:1.从FROM子句中获取数据源。
这可以是一个或多个表、视图或子查询。
2.使用WHERE子句进行筛选。
WHERE子句用于指定要返回的记录的条件。
只有满足条件的记录才会被包含在结果集中。
3.使用GROUPBY子句进行分组。
GROUPBY子句用于根据指定的列进行分组。
它将具有相同值的行分组在一起,并返回每个组的汇总信息。
4.使用HAVING子句筛选分组。
HAVING子句用于筛选分组的结果。
只有满足条件的分组才会被包含在结果集中。
5.使用SELECT子句选择列。
SELECT子句用于指定要包含在结果集中的列。
它可以包含聚合函数、算术运算和列名等。
6.使用ORDERBY子句排序结果。
ORDERBY子句用于根据指定的列对结果集进行排序。
可以按升序或降序排列。
7.使用LIMIT子句限制结果集的大小。
LIMIT子句用于指定要返回的最大行数。
每一步的详细解释如下:1.数据源:从FROM子句中获取数据源,可以是一个或多个表、视图或子查询。
这些数据源是要从中检索数据的对象。
2.筛选条件:使用WHERE子句指定用于筛选记录的条件。
只有满足条件的记录才会被包含在结果集中。
3.分组:使用GROUPBY子句根据指定的列对结果进行分组。
相同值的行会被分组在一起,并返回每个组的汇总信息。
4.分组筛选:使用HAVING子句筛选分组的结果。
只有满足条件的分组才会被包含在结果集中。
5.选择列:使用SELECT子句选择要包含在结果集中的列。
SELECT子句可以包含聚合函数、算术运算、列名等。
6.排序结果:使用ORDERBY子句根据指定的列对结果集进行排序。
可以按升序或降序排列。
7.限制结果集大小:使用LIMIT子句指定要返回的最大行数。
这可以用于限制结果集的大小,从而避免返回过多的数据。
以上是SQL语句的执行顺序和每一步的详细解释。
根据具体的SQL语句,可以根据这个顺序来理解它们的执行过程。
mysql中一条sql的执行过程
mysql中一条sql的执行过程一条SQL的执行过程SQL(Structured Query Language)是一种用于管理和操作关系型数据库的标准语言。
在MySQL中,执行一条SQL语句的过程可以分为解析、优化、执行三个主要阶段。
1. 解析阶段SQL语句在被执行之前,首先需要进行解析。
解析器会对SQL语句进行词法分析和语法分析,将其转化为一棵语法树。
在词法分析阶段,解析器会识别出SQL语句中的关键字、标识符和符号,并将其转化为一个个的标记。
在语法分析阶段,解析器会根据SQL语句的语法规则,构建一棵语法树,并进行语法检查,确保SQL语句的语法是正确的。
2. 优化阶段在解析阶段之后,MySQL会对解析得到的语法树进行优化。
优化器会分析查询语句的结构和相关的统计信息,生成不同的执行计划,并评估每个执行计划的成本。
通过比较不同执行计划的成本,优化器会选择一个最优的执行计划。
在优化阶段,MySQL会使用各种优化策略来提高查询的性能。
例如,MySQL可以通过索引来减少数据的访问次数,使用表连接来减少数据的传输量,使用子查询来优化复杂的查询逻辑等。
优化器会根据查询的具体情况选择合适的优化策略,以达到最佳的性能。
3. 执行阶段在经过解析和优化两个阶段之后,MySQL开始执行SQL语句。
执行器会按照优化器选择的执行计划,逐步执行查询的各个步骤。
执行器会打开相关的表,并根据查询条件进行数据的过滤。
在过滤的过程中,MySQL会根据索引的信息来定位符合条件的数据。
然后,执行器会根据查询的要求进行数据的排序、分组等操作。
最后,执行器会将查询结果返回给客户端。
在执行的过程中,MySQL会根据需要进行锁定和并发控制,以保证数据的一致性和并发的正确性。
MySQL还会记录查询的执行时间和操作日志,以便进行性能分析和故障排查。
总结:一条SQL的执行过程包括解析、优化和执行三个阶段。
在解析阶段,MySQL会对SQL语句进行词法分析和语法分析,生成语法树;在优化阶段,MySQL会根据统计信息和查询结构生成最优的执行计划;在执行阶段,MySQL会按照执行计划逐步执行查询的各个步骤,并进行数据过滤、排序、分组等操作。
Oracle中SQL语句解析的步骤
1.sql解析的过程oracle首先将SQL文本转化为ASCII字符,然后根据hash函数计算其对应的hash值(hash_value)。
根据计算出的hash值到library cache中找到对应的bucket,然后比较bucket里是否存在该SQL 语句。
如果不存在,获得shared pool latch,然后在shared pool中的可用chunk链表(也就是bucket)上找到一个可用的chunk,然后释放shared pool latch。
在获得了chunk以后,这块chunk就可以认为是进入了library cache。
然后,进行硬解析过程。
对SQL语句进行语法检查,看是否有语法错误。
比如没有写from等。
如果有,则退出解析过程。
到数据字典里校验SQL语句涉及的对象和列是否都存在。
如果不存在,则退出解析过程。
将对象进行名称转换。
比如将同名词翻译成实际的对象等。
如果转换失败,则退出解析过程。
检查游标里用户是否具有访问SQL语句里所引用的对象的权限。
如果没有权限,则退出解析过程。
通过优化器创建一个最优的执行计划。
这一步是最消耗CPU资源的。
将该游标所产生的执行计划、SQL文本等装载进library cache的若干个heap中。
在硬解析的过程中,进程会一直持有library cach latch,直到硬解析结束。
硬解析结束以后,会为该SQL产生两个游标,一个是父游标,另一个是子游标。
父游标里主要包含两种信息:SQL文本以及优化目标(optimizer goal)。
父游标在第一次打开时被锁定,直到其他所有的session都关闭该游标后才被解锁。
当父游标被锁定的时候是不能被交换出library cache的,只有在解锁以后才能被交换出library cache,这时该父游标对应的所有子游标也被交换出library cache。
子游标包括游标所有的信息,比如具体的执行计划、绑定变量等。
子游标随时可以被交换出library cache,当子游标被交换出library cache时,oracle可以利用父游标的信息重新构建出一个子游标来,这个过程叫reload。
SQL语句执行过程详解
SQL语句执行过程详解
1.解析:首先,数据库管理系统(DBMS)会对SQL语句进行解析,以
确定语法是否正确,并将其转换为一个内部执行计划。
解析器检查语句的
语法和正确性,然后生成一个语法树,该语法树表示了SQL语句的结构和
含义。
2.优化:一旦解析器将SQL语句转换为语法树,接下来的步骤是优化。
优化器会评估不同的执行计划,并选择最佳的执行计划。
优化器可以考虑
许多因素,如索引的可用性、查询统计信息、表的大小等。
3.访问控制:在执行SQL语句之前,数据库系统会检查用户对所涉及
数据的访问权限。
如果用户没有足够的权限,则无法执行该语句。
4.执行:一旦获得了适当的执行计划,并经过访问控制的验证,DBMS
开始执行SQL语句。
执行的过程包括从磁盘读取数据、计算结果和更新数
据等操作。
5.返回结果:最后,DBMS将执行结果返回给用户。
例如,对于查询
语句,返回的结果集将包含满足查询条件的数据行;对于更新语句,则返
回受影响的行数。
需要注意的是,SQL语句的执行过程是由DBMS自动完成的,而且每
个DBMS可能有不同的执行方式和策略。
因此,了解SQL的执行过程对于
理解数据库的工作原理和性能优化是至关重要的。
sql解析流程
sql解析流程SQL(Structured Query Language)是用于管理关系数据库的标准编程语言。
当你在数据库管理系统(如 MySQL, PostgreSQL, SQL Server 等)中执行一个 SQL 查询时,它经历了以下的基本流程:1. 词法分析(Lexical Analysis):输入的 SQL 语句首先被分解为一系列的词素或标记(tokens)。
例如,关键字、操作符、标识符、字符串字面量等都被识别出来。
2. 语法分析(Syntax Analysis):这些标记然后被组织成一个语法树(parse tree)或抽象语法树(Abstract Syntax Tree, AST)。
这个树形结构表示了 SQL 语句中的语法关系。
3. 语义分析(Semantic Analysis):在这一步,数据库系统会检查语法树中的语义准确性。
这包括检查表和列是否存在、数据类型是否正确、权限检查等。
4. 查询优化(Query Optimization):在这一步,系统会尝试找到执行查询的最有效的方法。
这可能涉及到多种策略,例如使用索引、合并连接操作等。
优化器会生成一个或多个执行计划,并选择其中的最佳方案。
5. 执行计划(Execution Plan):根据优化器选择的最佳方案,系统会生成一个执行计划。
这个计划详细说明了如何检索数据,包括读取哪些表、使用哪些索引等。
6. 执行(Execution):最后,系统根据执行计划执行查询,检索或修改数据,并返回结果。
7. 返回结果(Result Return):如果查询是 SELECT 类型,系统会返回查询结果。
如果是 DML(数据操纵语言)或 DDL(数据定义语言)类型的查询,系统会根据指令修改或创建数据。
8. 清理和关闭(Cleanup and Closure):在查询完成后,系统会释放为该查询分配的资源。
这包括关闭打开的表、释放锁等。
这个过程是大多数关系数据库管理系统处理 SQL 查询的基本方式。
beetlsql sql解析
beetlsql sql解析BeetlSQL是一个优秀的Java数据库访问库,它结合了模板引擎Beetl的优势,为开发者提供了一种更加简洁、高效的SQL操作方式。
本文将详细解析BeetlSQL的SQL解析过程,帮助读者深入了解其原理和用法。
一、BeetlSQL简介BeetlSQL是一个基于Java语言的SQL解析工具,它将SQL语句与Beetl 模板引擎相结合,使得开发者可以更加方便地编写、维护SQL语句。
BeetlSQL支持自定义SQL模板、动态SQL、SQL缓存等功能,大大提高了数据库操作的效率。
二、BeetlSQL SQL解析过程1.模板解析当我们使用BeetlSQL编写SQL模板时,首先需要定义一个Beetl模板文件,例如:```SELECT * FROM ${table} WHERE id = ${id}```其中,`${table}`和`${id}`是模板变量,可以在运行时动态替换。
解析过程如下:- BeetlSQL加载模板文件,并将模板内容转换为BeetlSQLTemplate 对象;- 当执行SQL查询时,BeetlSQL会将模板变量替换为实际的值;- 最终生成完整的SQL语句。
2.动态SQLBeetlSQL支持动态SQL,即在运行时根据条件生成不同的SQL语句。
例如:```SELECT * FROM ${table}${if(con1)} WHERE ${con1} ${end}${if(con2)} AND ${con2} ${end}```其中,`${con1}`和`${con2}`是条件表达式。
解析过程如下:- BeetlSQL在执行SQL查询前,会根据条件表达式的值决定是否包含对应的SQL片段;- 如果条件表达式的值为true,则将对应的SQL片段添加到最终的SQL语句中;- 如果条件表达式的值为false,则忽略对应的SQL片段。
3.SQL缓存为了提高性能,BeetlSQL提供了SQL缓存功能。
sql的执行过程详解
数据库一个sql的执行过程详解一个sql的执行过程一、组成部分PDO_MYSQL is a driver that implements the PHP Data Objects (PDO) interface to enable access from PHP to MySQL databases.•客户端,如:php 的pdo_mysql扩展。
•MySQL 服务: •server 层,主要包含:连接器、查询缓存、解析器、预处理器、优化器、执行器等,涵盖MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等)。
所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等 •存储引擎层,主要负责:数据的存储和提取。
二、大概流程•MySQL server 层的连接器对来自客户端的连接进行验证,包含: •`用户名密码` 或`SSL 证书` 验证 •`库-database`、`表-table`、`读写权限` 验证 •MySQL server 层的查询缓存对客户源原始SQL进行缓存命中检测:命中则直接返回,未命中则进一步执行查询。
•MySQL server 层的解析器对查询语句进行解析,得到查询语句的解析树。
•MySQL server 层的预处理器对解析树进一步验证。
•MySQL server 层的优化器将解析树转化为执行计划。
•MySQL server 层的执行器通过API 与底层的存储引擎进行交互,执行执行计划。
•MySQL 存储引擎层得到执行结果,返回给MySQL server 层。
MySQL server 层将结果交由查询缓存进行缓存,并返回给客户端 三、查询缓存•关键逻辑: •包含`now()` `current_date()` 等日期函数 •包含`用户自定义函数`、`存储函数` `用户变量` `临时表` 等 •涉及mysql 数据库的表或者字段 •`select * from user where id=1;` •`select * from user where id="1";` •`select username from user where id=1;` •`SELECT username FROM user WHERE id=1;` •`查询缓存` 缓存了`执行计划` 的完整结果,当缓存命中时,直接返回缓存中的结果,从而跳过了`解析-优化-执行` 的过程。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
为了将用户写的SQL文本转化为Oracle认识的且可执行的语句,这个过程就叫做解析过程。
解析分为硬解析和软解析。
一条SQL语句在第一次被执行时必须进行硬解析。
当客户端发出一条SQL语句(也可以是一个存储过程或者一个匿名PL/SQL块)进入shared pool时(注意,我们从前面已经知道,Oracle对这些SQL不叫做SQL语句,而是称为游标。
因为Oracle在处理SQL时,需要很多相关的辅助信息,这些辅助信息与SQL语句一起组成了游标),Oracle首先将SQL文本转化为ASCII值,然后根据hash函数计算其对应的hash值(hash_value)。
根据计算出的hash值到library cache中找到对应的bucket,然后比较bucket里是否存在该SQL语句。
如果不存在,则需要按照我们前面所描述的,获得shared pool latch,然后在shared pool 中的可用chunk链表(也就是bucket)上找到一个可用的chunk,之后释放shared pool latch。
在获得了chunk以后,这块chunk就可以认为是进入了library cache。
接下来,进行硬解析过程。
硬解析包括以下几个步骤。
对SQL语句进行文法检查,看是否有文法错误。
比如没有写from、select拼写错误等。
如果存在文法错误,则退出解析过程。
到数据字典里校验SQL语句涉及的对象和列是否都存在。
如果不存在,则退出解析过程。
这个过程会加载dictionary cache。
将对象进行名称转换。
比如将同名词翻译成实际的对象等。
比如select * from t中,t是一个同名词,指向hr.t1,于是Oracle将t转换为hr.t1。
如果转换失败,则退出解析过程。
检查发出SQL语句的用户是否具有访问SQL语句里所引用的对象的权限。
如果没有权限,则退出解析过程。
通过优化器创建一个最优的执行计划。
这个过程会根据数据字典里记录的对象的统计信息,来计算最优的执行计划。
这一步牵涉大量数学运算,是最消耗CPU资源的。
将该游标所产生的执行计划、SQL文本等装载进library cache的heap中。
在硬解析的过程中,进程会一直持有library cache latch,直到硬解析结束为止。
硬解析结束以后,会为SQL语句产生两个游标,一个是父游标,另一个是子游标。
父游标里主要包含两种信息:SQL文本以及优化目标(optimizer goal)。
父游标在第一次打开时被锁定,直到其他所有的session都关闭该游标后才被解锁。
当父游标被锁定的时候是不能被交换出library cache的,只有在解锁以后才能被交换出library cache。
父游标被交换出内存时,父游标对应的所有子游标也被交换出library cache。
子游标包括游标所有的信息,比如具体的执行计划、绑定变量等。
子游标随时可以被交换出library cache,当子游标被交换出library cache
从记录父游标的视图v$sqlarea的version_count列可以看到,该SQL语句有2个子游标。
而从记录子游标的视图v$sql里可以看到,该SQL文本确实有两条记录,而且它们的SQL
文本所处的地址(ADDRESS列)也是一样的,但是子地址(CHILD_ADDRESS)却不一样。
这里的子地址实际就是子游标所对应的heap 0的句柄。
由此我们也可以看到,存在许多因素可能导致SQL语句不能共享。
常见的因素包括SQL 文本大小写不一致、SQL语句的绑定变量的类型不一致、SQL语句涉及的对象名称虽然一致但是位于不同的schema下、SQL的优化器模式不一致(比如添加提示、修改了optimizer_mode参数等)等。