运维之Sql优化

分类:CentOS运维 阅读:3207 次

大概一个多月之前,接到过一个面试电话,其中有个问题是让我谈谈SQL优化,当时一时竟不知道怎么回答。这其中的不知道如何回答,并不是因为自己完全不懂SQL优化,而是在看过一些Oracle相关的书之后,深知这个话题不是一两句能够讲清的,所以不知道如何有条理的来描述SQL优化方法。 记得当时很不严密地说了两句,尽量使用索引,让SQL选择的集合尽量小。 这次事情之后,想起来有必要整理一下已知的关于SQL优化知识。

SQL优化是个系统工程,Tom老师的这篇文章说得很明白。它与数据库软件,操作系统及硬件都有非常大的关系,并没有一个包治百病的方案。因此在看过Oracle一些书之后,我便不再迷信网上到处转载的关于SQL优化的一些方法了。下面是我在看Sql Tuning这本书,整理出的一个学习优化SQL需要了解的东西。
需要进行SQL优化,首先需要了解SQL如何在数据库中执行。包括SQL解析,SQL转换,访问数据的路径,多张表之间采用何种方式联接,在不同数据集情况下执行计划会有什么不同,每一个SQL的命令对应于数据库的哪些操作(如order,having 等)。理解这些之后,还需要学习的就是如何通过一些方法来控制SQL的执行计划,如联接顺序等。在SQL Tuning一书中,看到过一些让我感觉匪夷所思的方法,目前还没读完,其中有许多有趣的东西,可惜只找到英文版,读着累。

其中的细节太多,下面说一个我了解的存在很多误解的东西。
Index在一些时候并不是最有效的方式,当SQL语句选取的数据集在超过全表的20%时,全表扫描的效率会高于使用Index,这也两种方式的数据访问有关。Index时,会先访问索引,取得Rowid(Rowid包括该条数据的物理地址信息),然后通过RowId读取访问该条记录所在的块。全表扫描则直接按顺序读取存储该表的数据块。Oracle在读取数据时,并不是一条一条读取数据,而是按块读取,因此有些时候一个数据块中可能会包含多条记录。再加入Oracle在全表扫描时可以并行读取数据块,速度远远高于小的IO,因此全表扫描速度比通过索引访问更快。