A. 通过分析SQL语句的执行计划优化SQL(三)
第 章握拿SQL语句处理的过程 在调整之前我们需要了解一些背景知识 只有知道这些背景知识 我们才能更好的去调整sql语句 本节介绍了SQL语句处理的基本过程 主要包括 · 查询语句处理 · DML语句处理(insert update delete) · DDL 语句处理(create drop alter ) · 事务控制(mit rollback) SQL 语句的执行过程(SQL Statement Execution) 图 概要的列出了处理和运行一个sql语句的需要各个重要阶段 在某些情况下 Oracle运行sql的过程可能与下面列出的各个阶段的顺序有所不同 如DEFINE阶段可能在FETCH阶段之前 这主要依赖你如何书写代码 对许多oracle的工具来说 其中某些阶段会自动执行 绝大多数用户不需要关心各个阶段的细节问题 然而 知道执行的各个阶段还是有必要的 这会帮助你写出更高效的SQL语句来 而且还可以让你猜测出性能差的SQL语句主要是由于哪一个阶段造成的 然后我们针对这个具体的阶段 找出解决的办法 图 SQL语句处理的各个阶段 DML语句的处理 本节给出一个例子来说明在DML语句处理的各个阶段到底发生了什么事情 假设你使用Pro*C程序来为指定部门的所有职员增加工资 程序已经连到正确的用户 你可以在你的程序中嵌入如下的SQL语句 EXEC SQL UPDATE employees SET salary = * salaryWHERE department_id = :var_department_id; var_department_id是程序变量 里面包含部亩配门号 我们要修改该部门的职员的工资 当这个SQL语句执行时 使用该变量的值 每种类型的语句都需要如下阶段 · 第 步: Create a Cursor 创建游标· 第 步: Parse the Statement分析语句· 第 步: Bind Any Variables 绑定变量· 第 步: Run the Statement 运行语句· 第 步: Close the Cursor 关闭游标如果使用了并行功能 还会包含下面这个阶段 · 第 步: Parallelize the Statement 并行执行语句段耐搭如果是查询语句 则需要以下几个额外的步骤 如图 所示 · 第 步: Describe Results of a Query 描述查询的结果集· 第 步: Define Output of a Query 定义查询的输出数据· 第 步: Fetch Rows of a Query 取查询出来的行下面具体说一下每一步中都发生了什么事情 第 步: 创建游标(Create a Cursor) 由程序接口调用创建一个游标(cursor) 任何SQL语句都会创建它 特别在运行DML语句时 都是自动创建游标的 不需要开发人员干预 多数应用中 游标的创建是自动的 然而 在预编译程序(pro*c)中游标的创建 可能是隐含的 也可能显式的创建 在存储过程中也是这样的 第 步:分析语句(Parse the Statement) 在语法分析期间 SQL语句从用户进程传送到Oracle SQL语句经语法分析后 SQL语句本身与分析的信息都被装入到共享SQL区 在该阶段中 可以解决许多类型的错误 语法分析分别执行下列操作 l 翻译SQL语句 验证它是合法的语句 即书写正确l 实现数据字典的查找 以验证是否符合表和列的定义l 在所要求的对象上获取语法分析锁 使得在语句的语法分析过程中不改变这些对象的定义l 验证为存取所涉及的模式对象所需的权限是否满足l 决定此语句最佳的执行计划l 将它装入共享SQL区l 对分布的语句来说 把语句的全部或部分路由到包含所涉及数据的远程节点 以上任何一步出现错误 都将导致语句报错 中止执行 只有在共享池中不存在等价SQL语句的情况下 才对SQL语句作语法分析 在这种情况下 数据库内核重新为该语句分配新的共享SQL区 并对语句进行语法分析 进行语法分析需要耗费较多的资源 所以要尽量避免进行语法分析 这是优化的技巧之一 语法分析阶段包含了不管此语句将执行多少次 而只需分析一次的处理要求 Oracle只对每个SQL语句翻译一次 在以后再次执行该语句时 只要该语句还在共享SQL区中 就可以避免对该语句重新进行语法分析 也就是此时可以直接使用其对应的执行计划对数据进行存取 这主要是通过绑定变量(bind variable)实现的 也就是我们常说的共享SQL 后面会给出共享SQL的概念 虽然语法分析验证了SQL语句的正确性 但语法分析只能识别在SQL语句执行之前所能发现的错误(如书写错误 权限不足等) 因此 有些错误通过语法分析是抓不到的 例如 在数据转换中的错误或在数据中的错(如企图在主键中插入重复的值)以及死锁等均是只有在语句执行阶段期间才能遇到和报告的错误或情况 查询语句的处理 查询与其它类型的SQL语句不同 因为在成功执行后作为结果将返回数据 其它语句只是简单地返回成功或失败 而查询则能返回一行或许多行数据 查询的结果均采用表格形式 结果行被一次一行或者批量地被检索出来 从这里我们可以得知批量的fetch数据可以降低网络开销 所以批量的fetch也是优化的技巧之一 有些问题只与查询处理相关 查询不仅仅指SELECT语句 同样也包括在其它SQL语句中的隐含查询 例如 下面的每个语句都需要把查询作为它执行的一部分 INSERT INTO table SELECT UPDATE table SET x = y WHERE DELETE FROM table WHERE CREATE table AS SELECT 具体来说 查询· 要求读一致性· 可能使用回滚段作中间处理· 可能要求SQL语句处理描述 定义和取数据阶段 第 步: 描述查询结果(Describe Results of a Query) 描述阶段只有在查询结果的各个列是未知时才需要 例如 当查询由用户交互地输入需要输出的列名 在这种情况要用描述阶段来决定查询结果的特征(数据类型 长度和名字) 第 步: 定义查询的输出数据(Define Output of a Query) 在查询的定义阶段 你指定与查询出的列值对应的接收变量的位置 大小和数据类型 这样我们通过接收变量就可以得到查询结果 如果必要的话 Oracle会自动实现数据类型的转换 这是将接收变量的类型与对应的列类型相比较决定的 第 步: 绑定变量(Bind Any Variables) 此时 Oracle知道了SQL语句的意思 但仍没有足够的信息用于执行该语句 Oracle 需要得到在语句中列出的所有变量的值 在该例中 Oracle需要得到对department_id列进行限定的值 得到这个值的过程就叫绑定变量(binding variables)此过程称之为将变量值捆绑进来 程序必须指出可以找到该数值的变量名(该变量被称为捆绑变量 变量名实质上是一个内存地址 相当于指针) 应用的最终用户可能并没有发觉他们正在指定捆绑变量 因为Oracle 的程序可能只是简单地指示他们输入新的值 其实这一切都在程序中自动做了 因为你指定了变量名 在你再次执行之前无须重新捆绑变量 你可以改变绑定变量的值 而Oracle在每次执行时 仅仅使用内存地址来查找此值 如果Oracle 需要实现自动数据类型转换的话(除非它们是隐含的或缺省的) 你还必须对每个值指定数据类型和长度 关于这些信息可以参考oracle的相关文档 如Oracle Call Interface Programmer s Guide 第 步: 并行执行语句(Parallelize the Statement ) ORACLE 可以在SELECTs INSERTs UPDATEs MERGEs DELETEs语句中执行相应并行查询操作 对于某些DDL操作 如创建索引 用子查询创建表 在分区表上的操作 也可以执行并行操作 并行化可以导致多个服务器进程(oracle server processes)为同一个SQL语句工作 使该SQL语句可以快速完成 但是会耗费更多的资源 所以除非很有必要 否则不要使用并行查询 第 步: 执行语句(Run the Statement) 到了现在这个时候 Oracle拥有所有需要的信息与资源 因此可以真正运行SQL语句了 如果该语句为SELECT查询或INSERT语句 则不需要锁定任何行 因为没有数据需要被改变 然而 如果语句为UPDATE或DELETE语句 则该语句影响的所有行都被锁定 防止该用户提交或回滚之前 别的用户对这些数据进行修改 这保证了数据的一致性 对于某些语句 你可以指定执行的次数 这称为批处理(array processing) 指定执行N次 则绑定变量与定义变量被定义为大小为N的数组的开始位置 这种方法可以减少网络开销 也是优化的技巧之一 第 步: 取出查询的行(Fetch Rows of a Query) 在fetch阶段 行数据被取出来 每个后续的存取操作检索结果集中的下一行数据 直到最后一行被取出来 上面提到过 批量的fetch是优化的技巧之一 第 步: 关闭游标(Close the Cursor) SQL语句处理的最后一个阶段就是关闭游标 DDL语句的处理(DDL Statement Processing) DDL语句的执行不同与DML语句和查询语句的执行 这是因为DDL语句执行成功后需要对数据字典数据进行修改 对于DDL语句 语句的分析阶段实际上包括分析 查找数据字典信息和执行 事务管理语句 会话管理语句 系统管理语句只有分析与执行阶段 为了重新执行该语句 会重新分析与执行该语句 事务控制(Control of Transactions) 一般来说 只有使用ORACLE编程接口的应用设计人员才关心操作的类型 并把相关的操作组织在一起 形成一个事务 一般来说 我门必须定义事务 这样在一个逻辑单元中的所有工作可以同时被提交或回滚 保证了数据的一致性 一个事务应该由逻辑单元中的所有必须部分组成 不应该多一个 也不应该少一个 · 在事务开始和结束的这段时间内 所有被引用表中的数据都应该在一致的状态(或可以被回溯到一致的状态)· 事务应该只包含可以对数据进行一致更改(one consistent change to the data)的SQL语句例如 在两个帐号之间的转帐(这是一个事务或逻辑工作单元) 应该包含从一个帐号中借钱(由一个SQL完成) 然后将借的钱存入另一个帐号(由另一个SQL完成) 这 个操作作为一个逻辑单元 应该同时成功或同时失败 其它不相关的操作 如向一个帐户中存钱 不应该包含在这个转帐事务中 在设计应用时 除了需要决定哪种类型的操作组成一个事务外 还需要决定使用BEGIN_DISCRETE_TRANSACTIO存储过程是否对提高小的 非分布式的事务的性能有作用 lishixin/Article/program/Oracle/201311/18806
B. 数据库,数据结构,编译原理对编程有那些影响和帮助
他们太重要了,
(1)数据结构:首先要明白---->程序=算法+数据
“数据结构”就是做数据这块的,例如一个“电影播放器”程序,首先要有“电影”吗,这个就是“数据”,那么就要用“数据结构”的知识,怎么存储每一帧,怎么高效,怎么能无损,怎么空间最节省.........,然后才是怎么去“解码”(解码就是“算法”做的啦),当然这么讲起来不是很严谨,但你可以看得出,数据结构可以说的上是有50%的重要性了。
(2)编译原理:不要以为,自己不去开发“语言”,编译原理就没有用啦,它能让你从根本上理解编译器,这对怎么提高程序的效率,怎么变出漂亮的程序很有用................当然貌似如果从事,“人工智能”这一块的话,编译原理也非常重要。
(3)数据库:又是刚才哪一点----------->程序=算法+数据
数据以文件的形式存储,是在不是很高效,所以,为了方便数据的管理与查找等等..........人类作出了“数据库”,说白了,它就是用来解决“数据”这部分内容的,现在基本无论你做什么都离不开数据库了,从大型网游到网站,到手机等的移动设备编程,都要用到数据库
--------------------------------------------------------------------------------------------------
从你的体温来看,你可能刚刚接触编程,没有做过什么成品,随着你越来越了解这个领域,你会刚到这些东西非常重要,当然还有很多东西,与以上三者地位相当,或更高,例如,微型计算机组成原理,等一些硬件方面的知识.......................................
---------------------------------------------------------------------------------------------------
还是“广泛阅读”吧。
C. sql语言用不用编译
不用
将指令直接输入其自带的“查询分析器”中运行就OK了
D. 嵌入式SQL的工作原理
提供对于嵌入式SQL的支持,需要数据库厂商除了提供DBMS之外,还必须提供一些工具。为了实现对于嵌入式SQL的支持,技术上必须解决以下4个问题[1]: 1.宿主语言的编译器不可能识别和接受SQL文,需要解决如何将SQL的宿主语言源代码编译成可执行码;2.宿主语言的应用程序如何与DBMS之间传递数据和消息;3.如何把对数据的查询结果逐次赋值给宿主语言程序中的变量以供其处理;4.数据库的数据类型与宿主语言的数据类型有时不完全对应或等价,如何解决必要的数据类型转换问题。 嵌入式SQL源码的处理流程 为了解决上述这些问题,数据库厂商需要提供一个嵌入式SQL的预编译器,把包含有嵌入式SQL文的宿主语言源码转换成纯宿主语言的代码。这样一来,源码即可使用宿主语言对应的编译器进行编译。通常情况下,经过嵌入式SQL的预编译之后,原有的嵌入式SQL会被转换成一系列函数调用。因此,数据库厂商还需要提供一系列函数库,以确保链接器能够把代码中的函数调用与对应的实现链接起来。
E. 要学习SQL Server数据库开发需要学习哪种数据库开发语言和哪种数据库开发工具呢
1、个人建议,掌握基本语句和利用好sqlsvr带的查询分析器工具,完全可以使用好数据库。
表的建立
关系数据库的主要特点之一就是用表的方式组织数据。表是SQL语言存放数据、查找数据以及更新数据的基本数据结丛返枯构。在SQL语言中,表有严格的定义,它是一种二维表,对于这种表有如下规定:
1)每一张表都有一个名字,通常称为表名或关系名。表名必须以字母开头,最大长度为30个字符。
2)一张表可以由若干列组成,列名唯一,列名也称作属性名。
3)表中的一行称为一个元组,它相当于一条记录。
4)同一列的数据必须具有相同的数据类型。
5)表中的每一个列值必须是不可分割的基本数据项。
注意:当用户需要新的数据结构或表存放数据时,世雹首先要生成一个表。
语法:
CREATE TABLE 表名 [表约束]
(列名1 数据类型 [缺省值1,列约束1]
(列名2 数据类型 [缺省值2,列约束2]
…
列名n 数据类型 [缺省值n,列约束n]
[TABLESPACE 表空间名称]
[STORAGE (存贮的子句)]
[ENABLE 约束名]
[DISABLE 约束名]
插入数据
当一个表新建成时,它里面没有数据,通过向表中扦入数据,建成表的实例。
语句句法:
INSERT INTO 表名[(列名1,…)]
VALUES(值1,值2,…,值n)
修改数据
对表中已有数据进行修改,语句句法:
UPDATE 表名SET 列名1=表达式1,列名2=表达式2,…
WHERE 条件;
删除数据
删除表中已有数据,不能渗洞删除不存在的数据。
语句句法:
DELETE FROM 表名 WHERE 条件;
查询语句
SELECT命令的语法为:
SELECT [DISTINCT|ALL] *
FROM 表名
[WHERE条件]
[GROUP BY表达式[,表达式] …[HAVING条件]
[UNION|UNION ALL |INTERSECT|MINUS]SELECT命令
[ORDER BY{表达式|位置} [ASC|DESC] [, {表达式|位置[ASC|DESC]}]…]
2、数据库开发语言:pb是一款比较不错的数据库开发语言,上手快,开发快捷。vb也可,上手容易。
3、linux不熟悉能学好Oracle,关联不大,oracle也可在winxp环境使用。
F. SQL语句在数据库中是怎样执行的(sql怎么执行语句)
第一步:应用程序把查枯运做询SQL语句发给服务器端执行
我们在数据层执行SQL语句时,应用程序会连接到相应的数据库服务器,把SQL语句发送给服务器处理。
第二步:服务器解析请求的SQL语句
SQL计划缓存,经常用查询分析器的朋友大概都知道这样一个事实,往往一个查询语句在第一次运行的时候需要执行特别长的时间,但是如果你马上或悄绝者在一定时间内运行同样的语句,会在很短的时间内返回查询结果。原因是:
服务器在接收到查询请求后,并不会马上去数据库查询,而是在数据库中的计划缓存中找是否有相对应的执行计划。如果存在,就直接调用已经编译好的执行计划,节省了执行计划的编译时间。
如果所查询的行已经存在于数据缓冲存储区中,就不用查询物理文件了,而是从缓存中取数据,这样从内存中取数据就会比从硬盘上读取数据快很多,提高了查询效率。数据缓冲存储区会在后面提到。
如果在SQL计划缓存中没有对应的执行计划,服务器首先会对用户请求的SQL语句进行语法效验,如果有语法错误,服务器会结束查询操作,并用返回相应的错误信息给调用它的应用程序。
注意:此时返回的错误信息中,只会包含基本的语法错误信息,例如select写成selec等,错误信息中如果包含一列表中本没有的列,此时服务器是不会检查出来的,因为只是语法验证,语义是否正确放在下一步进行。
语法符合后,就开始验证它的语义是否正确。例如,表名、列名、存储过程等等数据库对象是否真正存在,如果发现有不存在的,就会报错给应用程序,同时结束查询。
接下来就是获得对象的解析锁,我们在查询一个表时,首先服务器会对这个对象加锁,这是为了保证数据的统一性,如果不加锁,此时有数据插入,但因为没有加锁的原因,查询已经将这条记录读入,而有的插入会因为事务的失败会回滚,就会形成脏读的现象。
接下来就是对数据库用户权限的验证。SQL语句语法,语义都正确,此时并不一定能够得到查询结果,如果数据库用户没有相应的访问权限,服务器会报出权限不足的错误给应用程序,在稍大的项目中,往往一个项目里面会包含好几个数据库连接串,这些数据库用户具有不同的权限,有的是只读权限,有的是只写权限,有的是可读可写,根据不同的操作选取不同的用户来执行。稍微不注意,无论你的SQL语句写的多么完善,完美无缺都没用。
解析的最后一步,就是确定最终的执行计划。当语法、语义、权限都验证后,服务器并不会马上给你返回结果,而是会针对你的SQL进行优化,选择不同的查询算法以最高效的形式返回给应用程序。例如在做表联合查询时,服务器会根据开没衡销成本来最终决定采用hashjoin,mergejoin,还是loopjoin,采用哪一个索引会更高效等等。不过它的自动化优化是有限的,要想写出高效的查询SQL还是要优化自己的SQL查询语句。
当确定好执行计划后,就会把这个执行计划保存到SQL计划缓存中,下次在有相同的执行请求时,就直接从计划缓存中取,避免重新编译执行计划。
第三步:语句执行
服务器对SQL语句解析完成后,服务器才会知道这条语句到底表态了什么意思,接下来才会真正的执行SQL语句。
此时分两种情况:
如果查询语句所包含的数据行已经读取到数据缓冲存储区的话,服务器会直接从数据缓冲存储区中读取数据返回给应用程序,避免了从物理文件中读取,提高查询速度。
如果数据行没有在数据缓冲存储区中,则会从物理文件中读取记录返回给应用程序,同时把数据行写入数据缓冲存储区中,供下次使用。
说明:SQL缓存分好几种,这里有兴趣的朋友可以去搜索一下。有时因为缓存的存在,使得我们很难马上看出优化的结果,因为第二次执行因为有缓存的存在,会特别快速,所以一般都是先消除缓存,然后比较优化前后的性能表现,这里有几个常用的方法:
1DBCC
2从缓冲池中删除所有清除缓冲区。
3DBCC
4从过程缓存中删除所有元素。
5DBCC
6从所有缓存中释放所有未使用的缓存条目。
SQLServer2005数据库引擎会事先在后台清理未使用的缓存条目,以使内存可用于当前条目。但是,可以使用此命令从所有缓存中手动删除未使用的条目。
这只能基本消除SQL缓存的影响,目前好像没有完全消除缓存的方案,如果大家有,请指教。
执行顺序:
FROM子句返回初始结果集。
WHERE子句排除不满足搜索条件的行。
GROUPBY子句将选定的行收集到GROUPBY子句中各个唯一值的组中。
选择列表中指定的聚合函数可以计算各组的汇总值。
此外,HAVING子句排除不满足搜索条件的行。
计算所有的表达式;
使用orderby对结果集进行排序。
查找你要搜索的字段。
G. 数据库开发需要学什么
数据库开发工程师需要学习的课程有:
1、计算机导论
内容提要:为新学生提供一个关于计算机科学与技术学科的入门介绍,使他们对该学科有一个整体的认识,并了解该专业的学生应具有的基本知识和技能以及在该领域工作应有的职业道德与应遵守的法律准则。
2、数字电路与数字逻辑
内容提要:介绍数字逻辑与数字系统的基本概念、分析方法和设计原理,包括开关理论基础、组合逻辑、时序逻辑、可编程逻辑器件、数字系统等。
3、计算机组成原理与汇编语言
内容提要:以冯诺依曼计算机模型为出发点,介绍计算机的组织结构和工作原理,剖析计算机的运算器、存储器、控制器和输入输出设备的结构、工作原理和相互关系;介绍80X86指令系统、汇编语言与汇编指令、汇编程序与汇编过程、简单汇编程序设计、汇编语言与高级语言的接口、宏汇编等。
4、计算机网络
内容提要:介绍数据通信的基本概念和计算机网络的基本原理,包括计算机网络的体系结构、数据通信的基本方法和协议、计算机网络的主要应用协议;同时介绍计算机网络系统的安全和管理知识,使学生对数据通信和计算机网络有一个全面理解。
5、计算机体系结构
内容提要:研究计算机系统结构的基本概念、基本原理、基本结构和基本分析方法,使同学在具有一定的软硬件知识基础上能综合认识计算机系统余袭的软硬件功能分配与各种不同结构类型机器的特性和性能评价方法。为研究、开发、应用高级计算机系统打下基础。确立全面、系统的观点和学会定量分析问题的方法。
6、离散数学
内容提要:包括集合论、数理逻辑、图论、组合数学等内容,形式化的数学证明贯穿此课程。
7、高级程序设计语言
内容提要:分别以C、C#或JAVA为例,介绍程序设计和语言,程序的基本数据结构、类型定义、简单类型和结构化类型、程序的基本控制结构、结构化程序设计、面向对象的程序设计等。
8、算法分析与设计
内容提要:本课程延续数据结构课程的学习,从算法分析和设计的角度出发,除去传统的分类查找算法和一般的设计方法外,主要内容包括如下几个部分:算法研究的理论基础,递归分析技术,基本算法设计策略(几类经典算法学习),多项式运算与FFT,串匹配,概率分析算法橘毁昌。希望通过这一课程的学习,使学生能对现代的算法设计及分析的基本工具能有较全面的掌握。
9、数据结构
内容提要:介绍线性表及其链接存储结构与算法、数组与矩阵、堆栈与队列、广义表的存储结构与多元多项式表示、串与文本编辑、排序、树、图、文件结构。
10、数据库系统原理
内容提要:介绍数据库系统的基本概念、原理、方法及应用,主要包括数据库系统概论、数据库管理系统实现技术、数据库存储结构及其他类型的数据库系统。
11、编译技术
内容提要:介绍编译原理的理论和实践,包括编译程序设计、词法分析、语法分析、符号表、声明和存储管理、代码生成以及优化技术。
12、操作系统
内容提要:介绍操作系统的设计与实现,包括操作系统各组成部分的概述、互斥性和同步性、处理器实现、调度算法、存储算法、设备管理和文件系统。
数据库开发工程师是指设计、开发、维护管理大型数据库的专业人才。
第一类是MySQL,以自由软件为主,以社团式开发为代表。版本选择4.0,侧重于在Linux平台(RedHat8.0)。MySQL数据库短小精悍,速度比较快,它是自由软件产品,现在美国国家航天局的数据库系统就是MySQL。在很多中小型的ICP有着广泛的应用。
第二类是SQLServer2000,中小型企业数据库,界面友好,可操作性强,在数据库市场占有很大的份量,SQLServer2000是圆扒企业产品的代表,定位数据库中低端市场。
第三类是Oracle9i,中大型企业数据库,跨平台,在数据库中高市场占有很大的份量,Oracle9i介绍主要是Windows2000平台和Linux平台(RedHat8.0)。Oracle9i在金融、电信、银行有很多经典应用。
数据库开发需要学习数据结构与算法,操作系统程序,语言开发,数据库知识,基础知识,SQL语言数据流程,设置数据库系统的运行和管理。光写数据库开发还不行,还得要搭配一门开发语言,只有开发语言了,结合数据库开发才是一个合格的程序员。开发语言建议你学Java或者是PhP。
H. 做后端开发需要学什么
对于初学Java并且有志于后端开发的同学来说,需要重点关注以下几个部分:
基础:比如计算机系统、算法、编译原理等等
Web开发: 主要是Web开发相关的内容,包括HTML/CSS/js(前端页面)、 Servlet/JSP(J2EE)以及MySQL(数据库)相关的知识。它们的学习顺序应该是从前到后,因此最先学习的应该是HTML/CSS/JS(前端页面)。
J2EE:你需要学习的是Servlet/JSP(J2EE)部分,这部分是Java后端开发必须非常精通的部分,因此这部分是这三部分中最需要花精力的。关于Servlet/Jsp部分视频的选择,业界比较认可马士兵的视频。
最后一步,你需要学会使用数据库,弯态激mysql是个不错的入门选择,而且Java领域里主流的关系型数据库就是mysql。这部分一般在你学习Servlet/Jsp的时候,就会接触闭燃到的,其中的JDBC部分就是数据库相关的部分。你不仅要学会使用JDBC操作数埋袜据库,还要学会使用数据库客户端工具,比如navicat,sqlyog,二选一即可。
开发框架:目前比较主流的是SSM框架,即spring、springmvc、mybatis。你需要学会这三个框架的搭建,并用它们做出一个简单的增删改查的Web项目。你可以不理解那些配置都是什么含义,以及为什么要这么做,这些留着后面你去了解。但你一定要可以快速的利用它们三个搭建出一个Web框架,你可以记录下你第一次搭建的过程,相信我,你一定会用到的。还要提一句的是,你在搭建SSM的过程中,可能会经常接触到一个叫maven的工具。这个工具也是你以后工作当中几乎是必须要使用的工具,所以你在搭建SSM的过程中,也可以顺便了解一下maven的知识。在你目前这个阶段,你只需要在网络上了解一下maven基本的使用方法即可,一些高端的用法随着你工作经验的增加,会逐渐接触到的。
总而言之,这个阶段,你需要做的是深入了解Java底层和Java类库,也就是JVM和JDK的相关内容。而且还要更深入的去了解你所使用的框架,方式比较推荐看源码或者看官方文档。
I. SQL语句执行过程详解
SQL语句执行过程详解
一条sql,plsql的执行到底是怎样执行的呢?
一、SQL语句执行原理:
第一步:客户端把语句发给服务器端执行当我们在客户端执行 select 语句时,客户端会把这条 SQL 语句发送给服务器端,让服务器端的
进程来处理这语句。也就是说,Oracle 客户端是不会做任何的操作,他的主要任务就是把客户端产生
的一些 SQL 语句发送给服务器端。虽然在客户端也有一个数据库进程,但是,这个进程的作用跟服务器
上的进程作用事不相同的。服务器上的数据库进程才会对SQL 语句进行相关的处理。不过,有个问题需
要说明,就是客户端的进程跟服务器的进程是一一对应的。也就是说,在客户端连接上服务器后,在客户
端与服务器端都会形成一个进程,客户端上的我们叫做客户端进程;而服务器上的我们叫做服务器进程。
第二步:语句解析
当客户端把 SQL 语句传送到服务器后,服务器进程会对该语句进行解析。同理,这个解析的工作,
也是在服务器端所进行的。虽然这只是一个解析的动作,但是,其会做很多“小动作”。
1. 查询高速缓存(library cache)。服务器进程在接到客户端传送过来的 SQL 语句时,不
会直接去数据库查询。而是会先在数据库的高速缓存中去查找,是否存在相同语句的执行计划。如果在
数据高速缓存中,则服务器进程就会直接执行这个 SQL 语句,省去后续的工作。所以,采用高速数据缓
存的话,可以提高 SQL 语句的查询效率。一方面是从内存中读取数据要比从硬盘中的数据文件中读取
数据效率要高,另一方面,也是因为这个语句解析的原因。
不过这里要注意一点,这个数据缓存跟有些客户端软件的数据缓存是两码事。有些客户端软件为了
提高查询效率,会在应用软件的客户端设置数据缓存。由于这些数据缓存的存在,可以提高客户端应用软
件的查询效率。但是,若其他人在服务器进行了相关的修改,由于应用软件数据缓存的存在,导致修改的
数据不能及时反映到客户端上。从这也可以看出,应用软件的数据缓存跟数据库服务器的高速数据缓存
不是一码事。
2. 语句合法性检查(data dict cache)。当在高速缓存中找不到对应的 SQL 语句时,则服
务器进程就会开始检查这条语句的合法性。这里主要是对 SQL 语句的语法进行检查,看看其是否合乎
语法规则。如果服务器进程认为这条 SQL 语句不符合语法规则的时候,就会把这个错误信息,反馈给客
户端。在这个语法检查的过程中,不会对 SQL 语句中所包含的表名、列名等等进行 SQL 他只是语法
上的检查。
3. 语言含义检查(data dict cache)。若 SQL 语句符合语法上的定义的话,则服务器进程
接下去会对语句中的字段、表等内容进行检查。看看这些字段、表是否在数据库中。如果表名与列名不
准确的话,则数据库会就会反馈错误信息给客户端。所以,有时候我们写 select 语句的时候,若语法
与表名或者列名同时写错的话,则系统是先提示说语法错误,等到语法完全正确后,再提示说列名或表名
错误。
4. 获得对象解析锁(control structer)。当语法、语义都正确后,系统就会对我们需要查询
的对象加锁。这主要是为了保障数据的一致性,防止我们在查询的过程中,其他用户对这个对象的结构发
生改变。
5. 数据访问权限的核对(data dict cache)。当语法、语义通过检查之后,客户端还不一定
能够取得数据。服务器进程还会检查,你所连接的用户是否有这个数据访问的权限。若你连接上服务器
的用户不具有数据访问权限的话,则客户端就不能够取得这些数据。有时候我们查询数据的时候,辛辛苦
苦地把 SQL 语句写好、编译通过,但是,最后系统返回个 “没有权限访问数据”的错误信息,让我们气
半死。这在前端应用软件开发调试的过程中,可能会碰到。所以,要注意这个问题,数据库服务器进程先
检查语法与语义,然后才会检查访问权限。
6. 确定最佳执行计划 ?。当语句与语法都没有问题,权限也匹配的话,服务器进程还是不会直接对
数据库文件进行查询。服务器进程会根据一定的规则,对这条语句进行优化。不过要注意,这个优化是有
限的。一般在应用软件开发的过程中,需要对数据库的 sql 语言进行优化,这个优化的作用要大大地大
于服务器进程的自我优化。所以,一般在应用软件开发的时候,数据库的优化是少不了的。当服务器进程
的优化器确定这条查询语句的最佳执行计划后,就会将这条 SQL 语句与执行计划保存到数据高速缓存
(library cache)。如此的话,等以后还有这个查询时,就会省略以上的语法、语义与权限检查的步骤,
而直接执行 SQL 语句,提高 SQL 语句处理效率。
第三步:语句执行
语句解析只是对 SQL 语句的语法进行解析,以确保服务器能够知道这条语句到底表达的是什么意
思。等到语句解析完成之后,数据库服务器进程才会真正的执行这条 SQL 语句。这个语句执行也分两
种情况。
一是若被选择行所在的数据块已经被读取到数据缓冲区的话,则服务器进程会直接把这个数据传递
给客户端,而不是从数据库文件中去查询数据。
若数据不在缓冲区中,则服务器进程将从数据库文件中查询相关数据,并把这些数据放入到数据缓冲
区中(buffer cache)。
第四步:提取数据
当语句执行完成之后,查询到的数据还是在服务器进程中,还没有被传送到客户端的用户进程。所以,
在服务器端的进程中,有一个专门负责数据提取的一段代码。他的作用就是把查询到的数据结果返回给
用户端进程,从而完成整个查询动作。从这整个查询处理过程中,我们在数据库开发或者应用软件开发过
程中,需要注意以下几点:
一是要了解数据库缓存跟应用软件缓存是两码事情。数据库缓存只有在数据库服务器端才存在,在
客户端是不存在的。只有如此,才能够保证数据库缓存中的内容跟数据库文件的内容一致。才能够根据
相关的规则,防止数据脏读、错读的发生。而应用软件所涉及的数据缓存,由于跟数据库缓存不是一码事
情,所以,应用软件的数据缓存虽然可以提高数据的查询效率,但是,却打破了数据一致性的要求,有时候
会发生脏读、错读等情况的发生。所以,有时候,在应用软件上有专门一个功能,用来在必要的时候清除
数据缓存。不过,这个数据缓存的清除,也只是清除本机上的数据缓存,或者说,只是清除这个应用程序
的数据缓存,而不会清除数据库的数据缓存。
二是绝大部分 SQL 语句都是按照这个处理过程处理的。我们 DBA 或者基于 Oracle 数据库的
开发人员了解这些语句的处理过程,对于我们进行涉及到 SQL 语句的开发与调试,是非常有帮助的。有
时候,掌握这些处理原则,可以减少我们排错的时间。特别要注意,数据库是把数据查询权限的审查放在
语法语义的后面进行检查的。所以,有时会若光用数据库的权限控制原则,可能还不能满足应用软件权限
控制的需要。此时,就需要应用软件的前台设置,实现权限管理的要求。而且,有时应用数据库的权限管
理,也有点显得繁琐,会增加服务器处理的工作量。因此,对于记录、字段等的查询权限控制,大部分程
序涉及人员喜欢在应用程序中实现,而不是在数据库上实现。
DBCC DROPCLEANBUFFERS
从缓冲池中删除所有清除缓冲区。
DBCC FREEPROCCACHE
从过程缓存中删除所有元素。
DBCC FREESYSTEMCACHE
从所有缓存中释放所有未使用的缓存条目
SQL语句中的函数、关键字、排序等执行顺序:
1. FROM 子句返回初始结果集。
2. WHERE 子句排除不满足搜索条件的行。
3. GROUP BY 子句将选定的行收集到 GROUP BY 子句中各个唯一值的组中。
4. 选择列表中指定的聚合函数可以计算各组的汇总值。
5. 此外,HAVING 子句排除不满足搜索条件的行。
6. 计算所有的表达式;
7. 使用 order by 对结果集进行排序。
8. 查找你要搜索的字段。
二、SQL语句执行完整过程:
1.用户进程提交一个 sql 语句:
update temp set a=a*2,给服务器进程。
2.服务器进程从用户进程把信息接收到后,在 PGA 中就要此进程分配所需内存,存储相关的信息,如在会
话内存存储相关的登录信息等。
3.服务器进程把这个 sql 语句的字符转化为 ASCII 等效数字码,接着这个 ASCII 码被传递给一个
HASH 函数,并返回一个 hash 值,然后服务器进程将到shared pool 中的 library cache 中去查找是否存在相
同的 hash 值,如果存在,服务器进程将使用这条语句已高速缓存在 SHARED POOL 的library cache 中的已
分析过的版本来执行。
4.如果不存在,服务器进程将在 CGA 中,配合 UGA 内容对 sql,进行语法分析,首先检查语法的正确性,接
着对语句中涉及的表,索引,视图等对象进行解析,并对照数据字典检查这些对象的名称以及相关结构,并根据
ORACLE 选用的优化模式以及数据字典中是否存在相应对象的统计数据和是否使用了存储大纲来生成一个
执行计划或从存储大纲中选用一个执行计划,然后再用数据字典核对此用户对相应对象的执行权限,最后生成
一个编译代码。
5.ORACLE 将这条 sql 语句的本身实际文本、HASH 值、编译代码、与此语名相关联的任何统计数据
和该语句的执行计划缓存在 SHARED POOL 的 library cache中。服务器进程通过 SHARED POOL 锁存
器(shared pool latch)来申请可以向哪些共享 PL/SQL 区中缓存这此内容,也就是说被SHARED POOL 锁存
器锁定的 PL/SQL 区中的块不可被覆盖,因为这些块可能被其它进程所使用。
6.在 SQL 分析阶段将用到 LIBRARY
CACHE,从数据字典中核对表、视图等结构的时候,需要将数据
字典从磁盘读入 LIBRARY
CACHE,因此,在读入之前也要使用LIBRARY
CACHE 锁存器(library cache
pin,library cache lock)来申请用于缓存数据字典。 到现在为止,这个 sql 语句已经被编译成可执行的代码了,
但还不知道要操作哪些数据,所以服务器进程还要为这个 sql 准备预处理数据。
7.首先服务器进程要判断所需数据是否在 db buffer 存在,如果存在且可用,则直接获取该数据,同时根据
LRU 算法增加其访问计数;如果 buffer 不存在所需数据,则要从数据文件上读取首先服务器进程将在表头部
请求 TM 锁(保证此事务执行过程其他用户不能修改表的结构),如果成功加 TM 锁,再请求一些行级锁(TX
锁),如果 TM、TX 锁都成功加锁,那么才开始从数据文件读数据,在读数据之前,要先为读取的文件准备好
buffer 空间。服务器进程需要扫面 LRU list 寻找 free db buffer,扫描的过程中,服务器进程会把发现的所有
已经被修改过的 db buffer 注册到 dirty list 中, 这些 dirty buffer 会通过 dbwr 的触发条件,随后会被写出到
数据文件,找到了足够的空闲 buffer,就可以把请求的数据行所在的数据块放入到 db buffer 的空闲区域或者
覆盖已经被挤出 LRU list 的非脏数据块缓冲区,并排列在 LRU list 的头部,也就是在数据块放入 DB
BUFFER 之前也是要先申请 db buffer 中的锁存器,成功加锁后,才能读数据到 db buffer。
8.记日志 现在数据已经被读入到 db buffer 了,现在服务器进程将该语句所影响的并被读
入 db buffer 中的这些行数据的 rowid 及要更新的原值和新值及 scn 等信息从 PGA 逐条的写入 redo log
buffer 中。在写入 redo log buffer 之前也要事先请求 redo log buffer 的锁存器,成功加锁后才开始写入,当
写入达到 redo log buffer 大小的三分之一或写入量达到 1M 或超过三秒后或发生检查点时或者 dbwr 之前
发生,都会触发 lgwr 进程把 redo log buffer 的数据写入磁盘上的 redo file 文件中(这个时候会产生log file
sync 等待事件)
已经被写入 redofile 的 redo log buffer 所持有的锁存器会被释放,并可被后来的写入信息覆盖,
redo log buffer是循环使用的。Redo file 也是循环使用的,当一个 redo file 写满后,lgwr 进程会自动切换到
下一 redo file(这个时候可能出现 log fileswitch(checkpoint complete)等待事件)。如果是归档模式,归档进
程还要将前一个写满的 redo file 文件的内容写到归档日志文件中(这个时候可能出现 log file
switch(archiving needed)。
9.为事务建立回滚段 在完成本事务所有相关的 redo log buffer 之后,服务器进程开始改写这个 db buffer
的块头部事务列表并写入 scn,然后 包含这个块的头部事务列表及 scn 信息的数据副本放入回滚段中,将
这时回滚段中的信息称为数据块的“前映像“,这个”前映像“用于以后的回滚、恢复和一致性读。(回滚段可以
存储在专门的回滚表空间中,这个表空间由一个或多个物理文件组成,并专用于回滚表空间,回滚段也可在其它
表空间中的数据文件中开辟。
10.本事务修改数据块 准备工作都已经做好了,现在可以改写 db buffer 块的数据内容了,并在块的头部写
入回滚段的地址。
11.放入 dirty list 如果一个行数据多次 update 而未 commit,则在回滚段中将会有多个“前映像“,除了第
一个”前映像“含有 scn 信息外,其他每个“前映像“的头部都有 scn 信息和“前前映像”回滚段地址。一个
update 只对应一个 scn,然后服务器进程将在 dirty list 中建立一
条指向此 db buffer 块的指针(方便 dbwr 进程可以找到 dirty list 的 db buffer 数据块并写入数据文件中)。
接着服务器进程会从数据文件中继续读入第二个数据块,重复前一数据块的动作,数据块的读入、记日志、建
立回滚段、修改数据块、放入 dirty list。当 dirty queue 的长度达到阀值(一般是 25%),服务器进程将通知
dbwr 把脏数据写出,就是释放 db buffer 上的锁存器,腾出更多的 free db buffer。前面一直都是在说明
oracle 一次读一个数据块,其实 oracle 可以一次读入多个数据块(db_file_multiblock_read_count 来设置一
次读入块的个数)
说明:
在预处理的数据已经缓存在 db buffer 或刚刚被从数据文件读入到 db buffer 中,就要根据 sql 语句
的类型来决定接下来如何操作。
1>如果是 select 语句,则要查看 db buffer 块的头部是否有事务,如果有事务,则从回滚段中读取数据;如
果没有事务,则比较 select 的 scn 和 db buffer 块头部的 scn,如果前者小于后者,仍然要从回滚段中读取数据;
如果前者大于后者,说明这是一非脏缓存,可以直接读取这个 db buffer 块的中内容。
2>如果是 DML 操作,则即使在 db buffer 中找到一个没有事务,而且 SCN 比自己小的非脏
缓存数据块,服务器进程仍然要到表的头部对这条记录申请加锁,加锁成功才能进行后续动作,如果不成功,则要
等待前面的进程解锁后才能进行动作(这个时候阻塞是 tx 锁阻塞)。
用户 commit 或 rollback 到现在为止,数据已经在 db buffer 或数据文件中修改完
成,但是否要永久写到数文件中,要由用户来决定 commit(保存更改到数据文件) rollback 撤销数据的更改)。
1.用户执行 commit 命令
只有当 sql 语句所影响的所有行所在的最后一个块被读入 db buffer 并且重做信息被写入 redo log
buffer(仅指日志缓冲区,而不包括日志文件)之后,用户才可以发去 commit 命令,commit 触发 lgwr 进程,但不
强制立即 dbwr来释放所有相应 db buffer 块的锁(也就是no-force-at-commit,即提交不强制写),也就是说有
可能虽然已经 commit 了,但在随后的一段时间内 dbwr 还在写这条 sql 语句所涉及的数据块。表头部的行锁
并不在 commit 之后立即释放,而是要等 dbwr 进程完成之后才释放,这就可能会出现一个用户请求另一用户
已经 commit 的资源不成功的现象。
A .从 Commit 和 dbwr 进程结束之间的时间很短,如果恰巧在 commit 之后,dbwr 未结束之前断电,因为
commit 之后的数据已经属于数据文件的内容,但这部分文件没有完全写入到数据文件中。所以需要前滚。由
于 commit 已经触发 lgwr,这些所有未来得及写入数据文件的更改会在实例重启后,由 smon 进程根据重做日
志文件来前滚,完成之前 commit 未完成的工作(即把更改写入数据文件)。
B.如果未 commit 就断电了,因为数据已经在 db buffer 更改了,没有 commit,说明这部分数据不属于数
据文件,由于 dbwr 之前触发 lgwr 也就是只要数据更改,(肯定要先有 log) 所有 DBWR,在数据文件上的修改
都会被先一步记入重做日志文件,实例重启后,SMON 进程再根据重做日志文件来回滚。
其实 smon 的前滚回滚是根据检查点来完成的,当一个全部检查点发生的时候,首先让 LGWR 进程将
redo log buffer 中的所有缓冲(包含未提交的重做信息)写入重做日志文件,然后让 dbwr 进程将 db buffer 已
提交的缓冲写入数据文件(不强制写未提交的)。然后更新控制文件和数据文件头部的 SCN,表明当前数据库
是一致的,在相邻的两个检查点之间有很多事务,有提交和未提交的。
像前面的前滚回滚比较完整的说法是如下的说明:
A.发生检查点之前断电,并且当时有一个未提交的改变正在进行,实例重启之后,SMON 进程将从上一个
检查点开始核对这个检查点之后记录在重做日志文件中已提交的和未提交改变,因为
dbwr 之前会触发 lgwr,所以 dbwr 对数据文件的修改一定会被先记录在重做日志文件中。因此,断电前被
DBWN 写进数据文件的改变将通过重做日志文件中的记录进行还原,叫做回滚,
B. 如果断电时有一个已提交,但 dbwr 动作还没有完全完成的改变存在,因为已经提交,提交会触发 lgwr
进程,所以不管 dbwr 动作是否已完成,该语句将要影响的行及其产生的结果一定已经记录在重做日志文件中
了,则实例重启后,SMON 进程根据重做日志文件进行前滚.
实例失败后用于恢复的时间由两个检查点之间的间隔大小来决定,可以通个四个参数设置检查点执行的频
率:
Log_checkpoint_interval:
决定两个检查点之间写入重做日志文件的系统物理块(redo blocks)
的大小,默认值是 0,无限制。
log_checkpoint_timeout:
两 个 检 查 点 之 间 的 时 间 长 度(秒)默 认 值 1800s。
fast_start_io_target:
决定了用于恢复时需要处理的块的多少,默认值是 0,无限制。
fast_start_mttr_target:
直接决定了用于恢复的时间的长短,默认值是 0,无限制(SMON 进程执行的前滚
和回滚与用户的回滚是不同的,SMON 是根据重做日志文件进行前滚或回滚,而用户的回滚一定是根据回滚段
的内容进行回滚的。
在这里要说一下回滚段存储的数据,假如是 delete 操作,则回滚段将会记录整个行的数据,假如是 update,
则回滚段只记录被修改了的字段的变化前的数据(前映像),也就是没有被修改的字段是不会被记录的,假如是
insert,则回滚段只记录插入记录的 rowid。 这样假如事务提交,那回滚段中简单标记该事务已经提交;假如是
回退,则如果操作是 delete,回退的时候把回滚段中数据重新写回数据块,操作如果是 update,则把变化前数据
修改回去,操作如果是 insert,则根据记录的 rowid 把该记录删除。
2.如果用户 rollback。
则服务器进程会根据数据文件块和 DB BUFFER 中块的头部的事务列表和 SCN 以及回滚段地址找到
回滚段中相应的修改前的副本,并且用这些原值来还原当前数据文件中已修改但未提交的改变。如果有多个
“前映像”,服务器进程会在一个“前映像”的头部找到“前前映像”的回滚段地址,一直找到同一事务下的最早的
一个“前映像”为止。一旦发出了 COMMIT,用户就不能rollback,这使得 COMMIT 后 DBWR 进程还没有
全部完成的后续动作得到了保障。到现在为例一个事务已经结束了。
说明:
TM 锁:
符合 lock 机制的,用于保护对象的定义不被修改。 TX 锁:
这个锁代表一个事务,是行
级锁,用数据块头、数据记录头的一些字段表示,也是符合 lock 机制,有 resource structure、lock
structure、enqueue 算法。