SQL優化二(SQL性能調優)

来源:http://www.cnblogs.com/jmcui/archive/2017/08/20/7353874.html
-Advertisement-
Play Games

一·、前言:這篇博文內容非原創,是我們公司的架構師給我們做技術培訓的時候講的內容,我稍微整理了下,借花獻佛。這篇博文只是做一個大概的科普介紹,畢竟SQL優化的知識太大了,幾乎可以用一本書來介紹。另外,博主對SQL優化也是剛剛接觸,也有很多不瞭解的地方,說的不對的地方,還請大家指正,共勉! 二、ora ...


一·、前言:這篇博文內容非原創,是我們公司的架構師給我們做技術培訓的時候講的內容,我稍微整理了下,借花獻佛。這篇博文只是做一個大概的科普介紹,畢竟SQL優化的知識太大了,幾乎可以用一本書來介紹。另外,博主對SQL優化也是剛剛接觸,也有很多不瞭解的地方,說的不對的地方,還請大家指正,共勉!   二、oracle伺服器,所謂oracle伺服器指的是一個資料庫管理系統,它包括一個oracle實例(動態)和一個oracle資料庫(靜態)。 oracle實例是一個運行的概念,提供了一種訪問資料庫的方式,由SGA和一些後臺服務進程組成,DBWn PMON CKPT LGWR SMON是必備的後臺進程,而ad queue,rac,shared server,ad replication則是可選的。連接到oracle實例有三種途徑:  1、如果用戶登陸到運行oracle實例的操作系統上,則通過進程間通信進行訪問  2、C/S結構訪問  3、三層結構 oracle資料庫是一個被統一處理的數據的集合,從物理角度來說包括三類文件,數據文件、控制文件、重做日誌文件。 PMON監控其他後臺進程,並且在伺服器進程或者轉發器進程異常終止之後執行恢復。pmon負責清理資料庫的buffer cache,並且釋放客戶端進程使用的資源。比如說pmon重置當前活動的事務表,釋放不需要的locks,清理進程id(隱式回滾)   SMON負責系統級別的清理工作 1.執行實例恢復。 2.恢復異常的transaction(實例恢復期間 file or tablespace被置為offline狀態),smon會在他們置為online的時候執行恢復。 3.清理不使用的臨時segments。比如當創建index的時候需要分配臨時extent,如果操作失敗,smon負責清理這些臨時空間。 4.在使用字典管理表空間的時候合併連續的空閑extent。smon為定期監控。其他進程如果需要的話也會通知smon。   Database Writer Process (DBWn)負責將更改的buffer 從db buffer cache中寫到datafile中去,通過一個dbwn進程(dbw0)就足夠了,但是也可以配置更多額外的dbwr進程,它可以提升頻繁更改的資料庫系統的性能。當然額外的dbw進程對於單處理器系統是沒有任何用處的。   Log Writer Process (LGWR)管理這redo log buffer。lgwr寫buffer中連續的部分到online redo log 中。因為分離了更改資料庫buffer的任務:dbwn散列寫buffer到disk中,執行快速的順序寫到redo,所以資料庫提升了性能。 1.用戶提交了一個事務。 2. redo log switch 發生 3. 從上一次lgwr寫操作開始已經過去了3秒 4. redo log buffer 三分之一滿或者已經存儲了1mb的數據量 5. dbwn必須寫更改的數據到磁碟上面。   CKPT更新控制文件以及數據文件頭部的檢查點信息,並且給dbwn信號去寫數據塊到磁碟上面。檢查點信息包括:檢查點位置,scn,恢復時開始的redo log 位置,類似這樣的信息。   Recoverer Process (RECO)在分散式資料庫中,reco進程自動的解決分散式事務發生錯誤的情況。   三、分析語句階段優化   硬解析:SQL語句從用戶進程提交到oracle,經過分析裝載到共用SQL區域(shared pool)。如果SQL語句不在shared pool,需要進行語句解析,即硬解析。 軟解析:如果SQL語句在shared pool,就可以直接進入執行階段。 優化技巧1:語法分析需要耗費很多資源,要儘量避免進行語法分析,即硬解析。 優化技巧2:即軟解析時,當Shared pool沒有空間時,oracle會根據LRU演算法(最近最少使用頁面置換演算法)更新SQL區域,所以適當增加shared_pool,可以存放更多解析後的SQL來提高效率。   Oracle Optimizer(查詢優化器):是Oracle在執行SQL之前分析語句的工具,Oracle在執行一個SQL之前,首先要分析一下語句的執行計劃,然後再按執行計划去執行,主要有以下兩種方式:
  • RBO(rule-base optimizer):優化器遵循Oracle內部預定的規則,句法驅動和數據字典驅動。
  • CBO(cost-based optimizer):依據語句執行的代價,主要指對CPU和記憶體的占用,優化器在判斷是否使用CBO時,要參照表和索引的統計信息統計表驅動,統計信息要在對錶做analyze後才會有。
優化技巧3:Oracle8及以後版本,推薦用CBO方式,Oracle10G此功能已經很強大。   Oracle優化器的優化模式主要有五種: 
  • Choose:預設模式。根據表或索引的統計信息,如果有統計信息,則使用CBO方式;如果沒有統計信息,相應列有索引,則使用RBO方式。
  • Rule:基於規則優化,忽略任何統計信息
  • First rows:與Choose類似。不同的是如果表有統計信息,它將以最快的方式返回查詢結果,以獲得最佳響應時間。
  • First_rows_n:與Choose類似。不同的是如果表有統計信息,它將以最快的方式返回查詢的前幾行,以獲得最佳響應時間。
  • All rows:完全基於CBO的模式。當一個表有統計信息時,以最快方式返回表所有行,以獲得最大吞吐量。沒有統計信息則使用RBO方式。
 Oracle Optimizer 運行級別怎麼修改
  • Instance級:修改啟動參數在init<SID>.ora文件中設定OPTIMIZER_MODE,需要資料庫重啟
  • Session級:(JDBC或者Hibernate或者一次連接),通過alter session set optimizer_mode = value修改,忽略instance級
  • Statement級:通過在SQL語句中加如Hint(隱語)實現,表明對語句塊選擇基於開銷的優化方法,並獲得最佳響應時間,忽略instance級和session級

               eg:SELECT /*+ALL_ROWS*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';  ……來設定

DBMS_STATS包工具做CBO代價分析 DBMS_STATS:dbms_stats包下麵一共有40多個存儲過程. 對執行計劃的生成非常重要。常見的有: 分析資料庫(包括所有的用戶對象和系統對象):gather_database_stats
分析用戶所有的對象(包括表、索引、簇):gather_schema_stats
分析表:gather_table_stats
分析索引:gather_index_stats
刪除資料庫統計信息:delete_database_stats
刪除用戶方案統計信息:delete_schema_stats
刪除表統計信息:delete_table_stats
刪除索引統計信息:delete_index_stats
刪除列統計信息:delete_column_stats
設置表統計信息:set_table_stats
設置索引統計信息:set_index_stats
設置列統計信息:set_column_stats
可以查看表 DBA_TABLES來查看表是否與被分析過,如:
SELECT TABLE_NAME, LAST_ANALYZED FROM DBA_TABLES
通常使用的比較多的主要是DBMS_STATS.GATHER_TABLE_STATS和 DBMS_STATS.GATHER_INDEX_STATS。 使用步驟: 1、首先創建一個分析表,該表是用來保存之前的分析值。 SQL> begin
2 dbms_stats.create_stat_table(ownname => 'scott',stattab => 'STAT_TABLE');
3 end;
4 / 2、分析表信息。可以參考這篇博客 exec dbms_stats.gather_schema_stats(
ownname          => 'SCOTT',
options          => 'GATHER AUTO',
estimate_percent => dbms_stats.auto_sample_size,
method_opt       => 'for all columns size repeat',
degree           => 15
) 3、將執行計劃導入到STAT_TABLE中 exec dbms_stats.export_schema_stats(ownname => 'scott',stattab => 'stat_table') ;    4、查看執行計劃表 select * from  stat_table;   四、執行計劃階段優化   全表掃描(Full Table Scans) Oracle讀取表中所有的行,並檢查每一行是否滿足語句的WHERE限制條件,採用多塊讀的方式使一次I/O能讀取多塊數據塊,而不是只讀取一個數據塊,這極大的減少了I/O總次數,提高了系統的吞吐量,所以利用多塊讀的方法可以十分高效地實現全表掃描,註意,只有全表掃描才能使用多塊讀的操作。 優化技巧4:通過設置db_block_multiblock_read_count和db_block_size來適當增加一次I/O可讀的數據塊。 優化技巧5:避免使用select * from 減少物理讀,邏輯讀(* 要走系統字典表,查看這張表有哪些欄位),最好制定需要返回的欄位。 優化技巧6:較小的表使用全表掃描,效率更高;較大的表應避免全表掃描,除非涉及全表記錄10%以上的查詢;避免給記錄數少的表建立索引,避免索引開銷。 優化技巧7:指定過濾謂詞 where,儘可能縮小查詢範圍(能過濾掉大部分記錄的欄位應該放在右邊,因為sql語句是從右至左執行的)。   通過ROWID的表存取(Table Access by ROWID)

ROWID記錄了記錄行所在的數據文件、數據塊以及行在該塊中的位置,所以通過ROWID來存取數據可以快速定位到目標數據上,可以說是整個資料庫都在用的索引,是Oracle存取單行數據的最快方法。這種存取方法不會用到多塊讀操作,一次I/O只能讀取一個數據塊。

select empno from emp where rowid='AAAR3sAAEAAAACXAAA';

 

  索引掃描(Index Scan) 通過index查找到數據對應的rowid值(對於非唯一索引可能返回多個rowid值),然後根據rowid直接從表中得到具體的數據,這種查找方式稱為索引掃描或索引查找(index lookup)。

索引唯一掃描(index unique scan)

通過唯一索引查找一個數值經常返回單個ROWID,如果存在UNIQUE 或PRIMARY KEY 約束(約束只有一行記錄匹配),Oracle實現索引唯一性掃描。

select empno from emp where empno=7369;

 

索引範圍掃描(index range scan)

使用一個索引存取多行數據,在唯一索引上使用索引範圍掃描的典型情況下是在謂詞(where限制條件)中使用了範圍操作符,有以下三種情況會導致引起索引範圍掃描:

  • 在唯一索引列上使用了range操作符(> < <> >= <= between)
  • 在組合索引上,只使用部分列進行查詢,導致查詢出多行
  • 對非唯一索引列上進行的任何查詢。
select empno from emp where empno>7369;

 

索引全掃描(index full scan)

什麼時候會引起索引全掃描呢?當不使用謂詞邏輯where;所有查詢結果數據都必須從索引中可以直接得到;需要排序操作,比如order by。

 select empno from emp order by empno;

index full scan使用單塊讀方式有序讀取索引塊,產生db file sequential reads事件,當採用該方式讀取大量索引全掃描,效率低下

 

索引快速掃描(index fast full scan)

與索引全掃描很相似,只是不涉及排序動作。

select /*+ index_ffs(emp pk_emp) */empno from emp; //對指定的表執行快速全索引掃描,而不是全表掃描的辦法.  

index fast full scan使用多塊讀的方式讀取索引塊,產生db file scattered reads 事件,讀取時高效,但為無序讀取

 

 

優化技巧7:對於只從表中查詢出總行數的2%到4%行的表時,可以考慮創建索引。
優化技巧8:不要將那些頻繁修改的列作為索引列,頻繁修改會導致不必要的索引開銷。
優化技巧9:不要使用包含函數或操作符放入WHERE從句中的關鍵字作為索引,會導致索引失效,可以考慮使用函數索引。
優化技巧10:在組合索引中,沒有按照建立時的索引關鍵字順序描述,比如xyz變成了yxz,也會導致索引失效。
優化技巧11:如果在表中要建立索引的一列或多列上使用了函數或表達式,則創建的是基於函數的索引。基於函數的索引預先計算函數或表達式的值,並將結果存儲在索引中。B樹索引和bitmap索引也是函數索引
優化技巧12:排序動作能不做就不做,增加系統開銷的同時還會使快速索引失效。

 

五、多表關聯查詢操作 任何N(N大於2)張表之間的操作都將轉化為兩張表之間的關聯操作,查詢中,由上一操作返回的符合條件的行的集合,即可以是表的全部行數據的集合,也可以是表的部分行數據的集合,或者說集合篩選後的集合都成為row source。無論連接操作符如何,典型的連接類型共有3種:

排序合併連接(Sort Merge Join (SMJ))

select aa.CREATEPERSONNAME, bb.CREATEPERSON
from tbl_comm_commonticket aa, tbl_ybgz_ticket bb
where aa.CREATEPERSONNAME = bb.CREATEPERSON
order by aa.CREATEPERSONNAME, bb.CREATEPERSON

排序屬於代價很高的操作,特別對於大表。因此經常避免使用排序合併連接方法,但是如果2個row source都已經預先排序(比如primary Key索引),則這種連接方法可以選用。

 

嵌套迴圈(Nested Loops (NL))

分為驅動表(OUTER TABLE)和內層表(INNER TABLE)。因為嵌套迴圈,所以外層迴圈的次數越少越好,因此一般將數據量較小表或滿足條件的row source較小的表作為驅動表(用於外層迴圈)的理論依據。

select /*+USE_NL(emp,dept)*/ * from emp,dept where emp.deptno=dept.deptno;

嵌套迴圈返回已經連接的行,而不必等待所有的連接操作處理完才返回數據 ,所以提高了響應速度。如果OUTER TABLE比較小,並且在INNER TABLE上有唯一索引,或有高選擇性非唯一索引時,使用這種方法可以得到較好的效率。另外,這種連接方式,是在RBO優化器中。


哈希連接(Hash Join)

散列基本原理是:使用一個下標範圍比較大的數組來存儲元素。可以設計一個函數(哈希函數,也叫做散列函數),使得每個元素的關鍵字都與一個函數值(即數組下標,hash值)相對應,於是用這個數組單元來存儲這個元素;但是,不能夠保證每個元素的關鍵字與函數值是一一對應的,因此極有可能出現對於不同的元素,卻計算出了相同的函數值,這樣就產生了“衝突”,換句話說,就是把不同的元素分在了相同的“類”之中。 總的來說,“直接定址”與“解決衝突”是哈希表的兩大特點。

散列連接是CBO 做大數據集連接時的常用方式,優化器使用兩個表中較小的表(或數據源)利用連接鍵在記憶體中建立散列表,然後掃描較大的表並探測散列表,找出與散列表匹配的行。

hash join只有在CBO方式下可以使用;Oracle初始化參數HASH_JOIN_ENABLED決定是否啟用hash join;pga_aggregate_target指定散列連接可用的記憶體大小;儘量使內層表生成的散列表最小,最好能夠全部載入記憶體;主要用於等值連接。

select /*+USE_HASH(emp,dept)*/ * from emp,dept where emp.deptno=dept.deptno;

 

  六、其他

優化技巧13:避免使用不確定操作符,因為會引起全表掃描; <> ,!=可以等價轉化為 < or > 代替。
優化技巧14:Where子句中出現IS NULL或者IS NOT NULL時,Oracle會停止使用索引而執行全表掃描。可以在設計表時,對索引列設置為NOT NULL。這樣就可以用其他操作來取代判斷NULL的操作。
優化技巧15:當通配符“%”或者“_”作為查詢字元串的第一個字元時,索引不會被使用 。
優化技巧16:對數據類型不同的列進行比較時,會使索引失效。
優化技巧17:UNION操作符會對結果進行篩選,消除重覆,數據量大的情況下可能會引起磁碟排序。如果不需要刪除重覆記錄,應該使用UNION ALL。
優化技巧18:Order By語句中的非索引列會降低性能,可以通過添加索引的方式處理。嚴格控制在Order By語句中使用表達式。
優化技巧19:相同的Sql語句,要保證查詢字元完全相同,大小寫,空格位置,利用shared_pool,防止相同的Sql語句被多次分析,使用變數綁定。
優化技巧20:調整SQL語句的目的是為了在執行中使資源的使用減少到最小。除了選擇使用不同的SQL語法來優化執行代價,還可以通過調整執行順序優化SQL。
優化技巧21:Oracle在執行IN子查詢時,首先執行子查詢,將查詢結果放入臨時表再執行主查詢。而EXIST則是首先檢查主查詢,然後運行子查詢直到找到第一個匹配項。因此NOT EXISTS比NOT IN效率稍高,相應更快。但是(NOT) EXISTS 不等於(NOT) IN。
優化技巧22:可以多使用視圖進行軟解析,視圖只是把你要用的sql進行保存而已,你需要擔心的是視圖中的sql會不會效率太低,而不用擔心視圖的耗時。
優化技巧23:適當的時候強制使用rule會獲得更高效率;調試SQL時關註執行計劃和執行代價。
優化技巧24:避免視圖嵌套使用,尤其是針對視圖排序,篩選等操作。
優化技巧25:不同版本資料庫的執行計劃差別可能很大。
優化技巧26:不是只有select..是查詢,所有的DML操作都含有查詢過程。

  

七、SQL分析工具   EXPLAIN PLAN 使用步驟: 1、SQL> explain plan for select * from emp,dept where emp.deptno=dept.deptno; 2、select * from table(dbms_xplan.display); 3、

 

 AUTOTRACE 使用步驟: 1、set autotrace on (可能會報Cannot SET AUTOTRACE的錯誤,參考這篇博客解決) 2、select * from emp,dept where emp.deptno=dept.deptno; 3、

 

   
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 創建db_link,遠程導出/導入。expdp/impdp Oracle資料庫本地磁碟空間有限,或應用系統的需要,會通過遠程的方式導出資料庫。在oracle當中,exp遠程導庫的速度太慢,而expdp又無法直接通過遠程導庫。因此需要創建db_link遠程連接後,才能使用expdp遠程導庫。詳細步驟如 ...
  • 在資料庫中,經常有業務人員提出需求導出資料庫中的業務數據,而且是每天、每周或每月定時導出。為了方便,可將sql查詢的腳本 通過下麵腳本來導出EXCEL數據。 1.將查詢sql腳本(AAA.sql)放到 相關目錄如:/home/oracle/tongji-scripts/sql/AAA.sql 2.# ...
  • 最近買了阿裡雲,把項目部署上去以後,每天第一次訪問總是出一次異常,然後刷新一下就正常了。經查詢資料發現,原來mysql預設會自動關閉空閑時間超過8小時的連接,而連接池並不知道這個連接已經關閉了,所以就會出異常。 查看mysql 修改wait_timeout,雖然通過修改mysql的wait_time ...
  • 環境相關 系統:CentOS 6.8 64位jdk:1.7.0_79hadoop:hadoop 2.7.2 配置SSH免密碼登錄 測試下ssh是否可用 安裝hadoop2 下載hadoop-2.7.2.tar.gz,放在opt目錄下,解壓 配置Hadoop,路徑/opt/hadoop-2.5.1/e ...
  • 一、定義變數 --簡單賦值 declare @a int set @a=5 print @a --使用select語句賦值 declare @user1 nvarchar(50) select @user1='張三' print @user1 declare @user2 nvarchar(50) ...
  • 因公司項目需要,開始接觸大數據分析這塊知識。網上關於大數據這塊的知識還是比較多的。學習了一個禮拜了,再次記錄一下,自己的學習過程,希望可以幫助後學者少走一些彎路。 服務端的配置,由於公司項目經理已經配置好,我也就沒有過多的接觸,我所記錄的更多的是如果使用大數據。(JDK 和Eclipse不講了) 1 ...
  • mysql "ON DUPLICATE KEY UPDATE" 語法如果在INSERT語句末尾指定了ON DUPLICATE KEY UPDATE,並且插入行後會導致在一個UNIQUE索引或PRIMARY KEY中出現重覆值,則在出現重覆值的行執行UPDATE;如果不會導致唯一值列重覆的問題,則插入 ...
  • 1 欄位屬性 主鍵、唯一鍵和自增長。 1.1 主鍵 主鍵:primary key,一張表中只能有一個欄位可以使用對應的鍵,用來唯一的約束該欄位裡面的數據,不能重覆。 一張表只能有最多一個主鍵。 1.1.1 增加主鍵 在SQL操作中歐有多種方式可以給表增加主鍵,大體分為三種: 方案1:在創建表的時候, ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...