大概一個多月之前,接到過一個面試電話,其中有個問題是讓我談談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,因此全表掃描速度比通過索引訪問更快。