1. 技術解析Transwarp Inceptor是怎樣煉成的
技術解析Transwarp Inceptor是怎樣煉成的
當前Hadoop技術蓬勃發展,用於解決大數據的分析難題的技術平台開始涌現。Spark憑借性能強勁、高度容錯、調度靈活等技術優勢已漸漸成為主流技術,業界大部分廠商都提供了基於Spark的技術方案和產品。根據Databricks的統計,目前有11個商業的Spark版本。
在使用Spark作出計算平台的解決方案中,有兩種主流編程模型,一類是基於SparkAPI或者衍生出來的語言,另一種是基於sql語言。SQL作為資料庫領域的事實標准語言,相比較用API(如MapReceAPI,SparkAPI等)來構建大數據分析的解決方案有著先天的優勢:一是產業鏈完善,各種報表工具、ETL工具等可以很好的對接;二是用SQL開發有更低的技術門檻;三是能夠降低原有系統的遷移成本等。因此,SQL語言也漸漸成為大數據分析的主流技術標准。本文將深入解析Inceptor的架構、編程模型和編譯優化技術,並提供基準測試在多平台上的性能對比數據。
1.Inceptor架構
TranswarpInceptor是基於Spark的分析引擎,如圖1所示,從下往上有三層架構:最下面是存儲層,包含分布式內存列式存儲(TranswarpHolodesk),可建在內存或者SSD上;中間層是Spark計算引擎層,星環做了大量的改進保證引擎有超強的性能和高度的健壯性;最上層包括一個完整的SQL99和PL/SQL編譯器、統計演算法庫和機器學習演算法庫,提供完整的R語言訪問介面。
TranswarpInceptor可以分析存儲在HDFS、HBase或者TranswarpHolodesk分布式緩存中的數據,可以處理的數據量從GB到數十TB,即使數據源或者中間結果的大小遠大於內存容量也可高效處理。另外TranswarpInceptor通過改進Spark和YARN的組合,提高了Spark的可管理性。同時星環不僅僅是將Spark作為一個預設計算引擎,也重寫了SQL編譯器,提供更加完整的SQL支持。
同時,TranswarpInceptor還通過改進Spark使之更好地與HBase融合,可以為HBase提供完整的SQL支持,包括批量SQL統計、OLAP分析以及高並發低延時的SQL查詢能力,使得HBase的應用可以從簡單的在線查詢應用擴展到復雜分析和在線應用結合的混合應用中,大大拓展了HBase的應用范圍。
2.編程模型
TranswarpInceptor提供兩種編程模型:一是基於SQL的編程模型,用於常規的數據分析、數據倉庫類應用市場;二是基於數據挖掘編程模型,可以利用R語言或者SparkMLlib來做一些深度學習、數據挖掘等業務模型。
2.1SQL模型
TranswarpInceptor實現了自己的SQL解析執行引擎,可以兼容SQL99和HiveQL,自動識別語法,因此可以兼容現有的基於Hive開發的應用。由於TranswarpInceptor完整支持標準的SQL 99標准,傳統資料庫上運行的業務可以非常方便的遷移到Transwarp Inceptor系統上。此外Transwarp Inceptor支持PL/SQL擴展,傳統數據倉庫的基於PL/SQL存儲過程的應用(如ETL工具)可以非常方便的在Inceptor上並發執行。另外Transwarp Inceptor支持部分SQL 2003標准,如窗口統計功能、安全審計功能等,並對多個行業開發了專門的函數庫,因此可以滿足多個行業的特性需求。
2.2數據挖掘計算模型
TranswarpInceptor實現了機器學習演算法庫與統計演算法庫,支持常用機器學習演算法並行化與統計演算法並行化,並利用Spark在迭代計算和內存計算上的優勢,將並行的機器學習演算法與統計演算法運行在Spark上。例如:機器學習演算法庫有包括邏輯回歸、樸素貝葉斯、支持向量機、聚類、線性回歸、關聯挖掘、推薦演算法等,統計演算法庫包括均值、方差、中位數、直方圖、箱線圖等。TranswarpInceptor可以支持用R語言或者SparkAPI在平台上搭建多種分析型應用,例如用戶行為分析、精準營銷、對用戶貼標簽、進行分類。
3.SQL編譯與優化
TranswarpInceptor研發了一套完整的SQL編譯器,包括HiveQL解析器、SQL標准解析器和PL/SQL解析器,將不同的SQL語言解析成中間級表示語言,然後經過優化器轉換成物理執行計劃。SQL語言解析後經過邏輯優化器生成中間級表示語言,而中間表示語言再經過物理優化器生成最終的物理執行計劃。從架構上分,邏輯優化器和物理優化器都包含基於規則的優化模塊和基於成本的優化模塊。
為了和Hadoop生態更好的兼容,Inceptor為一個SQL查詢生成MapRece上的執行計劃和Spark上的執行計劃,並且可以通過一個SET命令在兩種執行引擎之間切換。
3.1SQL編譯與解析
TranswarpInceptor的SQL編譯器會根據輸入的SQL查詢的類型來自動選擇不同的解析器,如PL/SQL存儲過程會自動進入PL/SQL解析器並生成一個SparkRDD的DAG從而在Spark平台上並行計算,標准SQL查詢會進入SQL標准解析器生成Spark或MapRece執行計劃。由於HiveQL和標準的SQL有所出入,為了兼容HiveQL,Transwarp Inceptor保留了HiveQL解析器,並可以對非標准SQL的Hive查詢生成Spark或者Map Rece執行計劃。
3.1.1SQL標准解析器
TranswarpInceptor構建了自主研發的SQL標准解析器,用於解析SQL99& SQL 2003查詢並生成Spark和Map Rece的執行計劃。詞法和語法分析層基於Antlr語法來構建詞法範式,通過Antlr來生成抽象語義樹,並會通過一些上下文的語義來消除沖突並生成正確的抽象語義樹。語義分析層解析上層生成的抽象語義樹,根據上下文來生成邏輯執行計劃並傳遞給優化器。首先Transwarp Inceptor會將SQL解析成TABLE SCAN、SELECT、FILTER、JOIN、UNION、ORDER BY、GROUP BY等主要的邏輯塊,接著會根據一些Meta信息進一步細化各個邏輯塊的執行計劃。如TABLE SCAN會分成塊讀取、塊過濾、行級別過濾、序列化等多個執行計劃。
3.1.2PL/SQL解析器
PL/SQL是Oracle對SQL語言的模塊化擴展,已經在很多行業中有大規模的應用,是數據倉庫領域的重要編程語言。
為了讓存儲過程在Spark上有較好的性能,PL/SQL解析器會根據存儲過程中的上下文關系來生成SQLDAG,然後對各SQL的執行計劃生成的RDD進行二次編譯,通過物理優化器將一些沒有依賴關系的RDD進行合並從而生成一個最終的RDDDAG。因此,一個存儲過程被解析成一個大的DAG,從而stage之間可以大量並發執行,避免了多次執行SQL的啟動開銷並保證了系統的並發性能。
解析並生成SQL級別的執行計劃
3.2SQL優化器
TranswarpInceptor使用Spark作為默認計算引擎,並且開發了完善的SQL優化器,因此在大量的客戶案例性能測試中,TranswarpInceptor的性能領先MapRece 10-100倍,並超越部分開源MPP資料庫。SQL優化器對平台性能的提升居功至偉。
3.2.1基於規則的優化器(RuleBasedOptimizer)
目前為止,TranswarpInceptor共實現了一百多個優化規則,並且在持續的添加新的規則。按照功能劃分,這些規則主要分布在如下幾個模塊:
文件讀取時過濾
在文件讀取時過濾數據能夠最大化的減少參與計算的數據量從而最為有效的提高性能,因此TranswarpInceptor提供了多個規則用於生成表的過濾條件。對於一些SQL中的顯示條件,TranswarpInceptor會盡量將過濾前推到讀取表中;而對於一些隱式的過濾條件,如可以根據joinkey生成的過濾規則,Inceptor會根據語義保證正確性的前提下進行規則生成。
過濾條件前置
TranswarpInceptor能夠從復雜的組合過濾條件中篩選出針對特定表的過濾規則,然後通過SQL語義來確定是否能將過濾條件前推到盡量早的時候執行。如果有子查詢,過濾條件可以遞歸前推入最低層的子查詢中,從而保證所有的冗餘數據被刪除。
超寬表的讀取過濾
對一些列超多的表進行處理的時候,TranswarpInceptor首先會根據SQL語義來確定要讀取的列,並在讀取表的時候進行跨列讀取減少IO和內存消耗。而如果表有過濾條件,Inceptor會做進一步優化,首先只讀取過濾條件相關的列來確定該行記錄是否需要被選擇,如果不是就跳過當前行的所有列,因此能夠最大程度上的減少數據讀取。在一些商業實施中,這些優化規則能夠帶來5x-10x的性能提升。
Shuffle Stage的優化與消除
Spark的shuffle實現的效率非常低,需要把結果寫磁碟,然後通過HTTP傳輸。TranswarpInceptor添加了一些shuffle消除的優化規則,對SQL的DAG中不必要或者是可以合並的shufflestage進行消除或者合並。對於必須要做Shuffle的計算任務,Inceptor通過DAGScheler來提高shuffle的效率:MapTask會直接將結果返回給DAGScheler,然後DAGScheler將結果直接交給Rece Task而不是等待所有Map Task結束,這樣能夠非常明顯的提升shuffle階段的性能。
Partition消除
TranswarpInceptor提供單一值Partition和RangePartition,並且支持對Partition建Bucket來做多次分區。當Partition過多的時候,系統的性能會因為內存消耗和調度開銷而損失。因此,Inceptor提供了多個規則用於消除不必要的Partition,如果上下文中有隱式的對Partition的過濾條件,Inceptor也會生成對partition的過濾規則。
3.2.2基於成本的優化器(CostBasedOptimizer)
基於規則的優化器都是根據一些靜態的信息來產生的,因此很多和動態數據相關的特性是不能通過基於規則的優化來解決,因此TranswarpInceptor提供了基於成本的優化器來做二次優化。相關的原始數據主要來自Meta-store中的表統計信息、RDD的信息、SQL上下文中的統計信息等。依賴於這些動態的數據,CBO會計算執行計劃的物理成本並選擇最有效的執行計劃。一些非常有效的優化規則包括如下幾點:
JOIN順序調優
在實際的案例中,join是消耗計算量最多的業務,因此對join的優化至關重要。在多表JOIN模型中,TranswarpInceptor會根據統計信息來預估join的中間結果大小,並選擇產生中間數據量最小的join順序作為執行計劃。
JOIN類型的選擇
TranswarpInceptor支持Left-mostJoinTree 和 Bush Join Tree,並且會根據統計信息來選擇生成哪種Join模型有最佳性能。此外,Transwarp Inceptor會根據原始表或者中間數據的大小來選擇是否開啟針對數據傾斜模型下的特殊優化等。此外,針對HBase表是否有索引的情況,Transwarp Inceptor會在普通Join和Look-up Join間做個均衡的選擇。
並發度的控制
Spark通過線程級並發來提高性能,但是大量的並發可能會帶來不必要的調度開銷,因此不同的案例在不同並發度下會有最佳性能。TranswarpInceptor通過對RDD的一些屬性進行推算來選擇最佳並發控制,對很多的案例有著2x-3x的性能提升。
4.TranswarpHolodesk內存計算引擎
為了有效的降低SQL分析的延時,減少磁碟IO對系統性能的影響,星環科技研發了基於內存或者SSD的存儲計算引擎TranswarpHolodesk,通過將表數據直接建在內存或者SSD上以實現SQL查詢全內存計算。另外TranswarpHolodesk增加了數據索引功能,支持對多個數據列建索引,從而更大程度的降低了SQL查詢延時。
4.1存儲格式
TranswarpHolodesk基於列式存儲做了大量的原創性改進帶來更高的性能和更低的數據膨脹率。首先數據被序列化後存儲到內存或SSD上以節省者資源佔用。如圖3所示,每個表的數據被存儲成若干個Segment,每個Segment被劃分成若干個Block,每個Block按照列方式存儲於SSD或內存中。另外每個Block的頭部都加上Min-MaxFilter和BloomFilter用於過濾無用的數據塊,減少不必要的數據進入計算階段。
TranswarpHolodesk根據查詢條件的謂詞屬性對每個數據塊的對應列構建數據索引,索引列採用自己研發的Trie結構進行組織存儲,非索引列採用字典編碼的方式進行組織存儲。Trie不僅能對具有公共前綴的字元串進行壓縮,而且可以對輸入的字元串排序,從而可以利用二分查找快速查詢所需數據的位置,從而快速響應查詢需求。
HDFS2.6支持StorageTier讓應用程序可以選擇存儲層為磁碟或者SSD,但是沒有專用的存儲格式設計是無法有效利用SSD的讀寫吞吐量和低延,因此現有的Text以及行列混合(ORC/Parquet)都不能有效的利用SSD的高性能。為此驗證存儲結構對性能的影響,我們將HDFS構建在SSD上並選用某基準測試來做了進一步的性能對比,結果如圖4所示:採用文本格式,PCI-ESSD帶來的性能提升僅1.5倍;採用專為內存和SSD設計的Holodesk列式存儲,其性能相比較SSD上的HDFS提升高達6倍。
4.2性能優勢
某運營商客戶在12台x86伺服器上搭建了TranswarpInceptor,將TranswarpHolodesk配置在PCIE-SSD上,並與普通磁碟表以及DB2來做性能對比測試。最終測試數據如圖5所示:
在純粹的count測試一項,Holodesk性能相對於磁碟表最高領先32倍;對於join測試一項,TranswarpHolodesk最高領先磁碟表多達12倍;在單表聚合測試中,Holodesk提升倍數達10~30倍。另外TranswarpHolodesk在和DB2的對比中也表現優秀,兩個復雜SQL查詢在DB2資料庫中需要運行1小時以上,但是在使用TranswarpHolodesk均是分鍾級和秒級就返回結果。
內存的價格大約是同樣容量SSD的十倍左右,為了給企業提供更高性價比的計算方案,TranswarpHolodesk針對SSD進行了大量的優化,使得應用在SSD上運行具有與在內存上比較接近的性能,從而為客戶提供了性價比更高的計算平台。
在對TPC-DS的IO密集型查詢的測試中,無論上構建在PCI-ESSD還是內存上,Holodesk對比磁碟表有一個數量級上的性能提升;而SSD上的Holodesk性能只比內存差10%左右。
5.穩定的Spark執行引擎
企業目前應用開源Spark的主要困難在穩定性、可管理性和功能不夠豐富上。開源Spark在穩定性上還有比較多的問題,在處理大數據量時可能無法運行結束或出現Outofmemory,性能時快時慢,有時比Map/Rece更慢,無法應用到復雜數據分析業務中。
TranswarpInceptor針對各種出錯場景設計了多種解決方法,如通過基於成本的優化器選擇最合適的執行計劃、加強對數據結構內存使用效率的有效管理、對常見的內存出錯問題通過磁碟進行數據備份等方式,極大提高了Spark功能和性能的穩定性,上述問題都已經解決並經過商業案例的考驗。TranswarpInceptor能穩定的運行7*24小時,並能在TB級規模數據上高效進行各種穩定的統計分析。
6.SQL引擎效能驗證
TPC-DS是TPC組織為DecisionSupportSystem設計的一個測試集,包含對大數據集的統計/報表生成/聯機查詢/數據挖掘等復雜應用,測試用的數據有各種不同的分布與傾斜,與真實場景非常接近。隨著國內外各代表性的Hadoop發行版廠商以TPC-DS為標准測評產品,TPC-DS也就逐漸成為了業界公認的Hadoop系統測試准則。
6.1驗證對比的平台和配置
我們搭建了兩個集群分別用於TranswarpInceptor與ClouderaDataHub/Impala的測試。
6.2TranswarpInceptorVS Cloudera Impala
TranswarpInceptor由於有完善的SQL支持,能夠運行全部所有的99個SQL查詢。而由於Cloudera官方發布的TPC-DS測試集只包含19個SQL案例,因此我們只能運行這19個SQL,實驗證明這部分查詢在Impala上全部正常運行完成。
6.3TranswarpInceptorVS Map Rece
我們使用了同樣的硬體和軟體配置完成和開源的Hive執行效率相比,TranswarpInceptor能夠帶來10x-100x的性能提升。圖8是TPC-DS的部分SQL查詢在Inceptor和CDH5.1Hive的性能提升倍數,其中最大的提升倍數竟可達到123倍。
7.結語
隨著在大數據領域國內外開始處於同一起跑線,我們相信像星環科技這樣國內具有代表性的Hadoop發行版廠商將在中國的廣闊市場空間中獲得長足發展,並且由於中國市場激烈的競爭與磨練,逐步打磨出超越國外先進廠商的技術與實力。
劉汪根。2013年加入星環,作為早期員工參與了星環大數據平台的構建,現擔任數據平台部研發經理,主要負責與管理星環大數據平台數據平台的研發工作,如SQL編譯器,Spark執行引擎等工作,產品涵括TranswarpInceptor/TranswarpStream等軟體。
【編者按】星環科技從2013年6月開始研發基於Spark的SQL執行引擎,在2013年底推出TranswarpInceptor1.0,並落地了國內首個7x24小時的商用項目。經過1年多的持續創新與改進,星環已經在國內落地了數十個Inceptor的商用項目。這是一篇星環Spark解決方案的技術解析,也是Spark用戶可以效仿的優化之道。
2. 資料庫牛人是如何進行SQL優化的
SQL 查詢優化減少了查詢所需的資源並提高了整體系統性能,在本文中,我們將討論 SQL 查詢優化、它是如何完成的、最佳實踐及其重要性。
SQL 查詢優化是編寫高效的 SQL 查詢,並在執行時間和資料庫表示方面 提高查詢性能 的迭代過程,查詢優化是幾個關系資料庫管理系統 (RDBMS) 的一項重要功能。
查詢是對來自資料庫的數據或信息的問題或請求,需要編寫一組資料庫可以理解的預定義代碼,結構化查詢語言 (SQL) 和其他查詢語言旨在檢索或管理關系資料庫中的數據。
資料庫中的查詢可以用許多不同的結構編寫,並且可以通過不同的演算法執行,寫得不好的查詢會消耗更多的系統資源,執行時間長,並可能導致服務損失,一個完美的查詢可以減少執行時間並帶來最佳的 SQL 性能。
SQL查詢優化的主要目的是:
確保查詢處於最佳路徑和形式非常重要,SQL 查詢過程需要最好的執行計劃和計算資源,因為它們是 CPU 密集型操作,SQL 查詢優化通過三個基本步驟完成:
解析確保查詢在語法和語義上都是正確的,如果查詢語法正確,則將其轉換為表達式並傳遞到下一步。
優化在查詢性能中扮演著重要的角色,並且可能很困難,任何考慮優化的查詢執行計劃都必須返回與之前相同的結果,但優化後的性能應該會有所提高。
SQL 查詢優化包括以下基本任務:
最後,查詢執行涉及將查詢優化步驟生成的計劃轉化為操作,如果沒有發生錯誤,此步驟將返回結果給用戶。
一旦用戶確定某個查詢需要改進以優化 SQL 性能,他們就可以選擇任何優化方法——優化 SQL 查詢性能的方法有很多種,下面介紹了一些最佳實踐。
提高查詢性能的一種簡單方法是將 SELECT * 替換為實際的列名,當開發人員在表中使用 SELECT * 語句時,它會讀取每一列的可用數據。
使用 SELECT 欄位名 FROM 而不是 SELECT * FROM 時,可以縮小查詢期間從表中提取的數據的范圍,這有助於提高查詢速度。
循環中的 SQL 查詢運行不止一次,這會顯著降低運行速度,這些查詢會不必要地消耗內存、CPU 能力和帶寬,這會影響性能,尤其是當 SQL 伺服器不在本地計算機上時,刪除循環內的查詢可提高整體查詢性能。
使用SQL 伺服器索引可以減少運行時間並更快地檢索數據,可以使用聚集和非聚集 SQL 索引來優化 SQL 查詢,非聚集索引單獨存儲,需要更多的磁碟空間,因此,了解何時使用索引很重要。
該OLAP功能「擴展了SQL解析函數的語法。」 SQL 中的 OLAP 功能更快且易於使用,熟悉這些語法的 SQL 開發人員和 DBA 可以很容易地適應和使用它們。
OLAP 函數可以創建所有標准計算度量,例如排名、移動聚合、份額、期初至今、前期和未來期、平行期等。
查詢優化器使用統計信息來確定如何最好地連接表、何時應該使用索引以及如何訪問這些索引等,無論是手動還是自動,SQL 伺服器統計信息都應該保持最新。
過時的 SQL Server 統計信息會影響表、索引或列統計信息,並導致查詢計劃性能不佳。
SQL 查詢優化可以輕松提高系統性能,從而節省成本,優化 SQL 查詢可以提高運營效率並加快性能,從而提高系統上線進度。
SQL 查詢優化很重要,原因有很多,包括:
組織可以通過更快的響應時間獲得可靠的數據訪問和高水平的性能,優化 SQL 查詢不僅可以提高整體系統性能,還可以提高組織的聲譽,最終,SQL 查詢優化的最佳實踐幫助用戶獲得准確、快速的資料庫結果。
3. SQL語句執行流程與順序原理解析
SQL語句執行流程與順序原理解析
Oracle語句執行流程
第一步:客戶端把語句發給伺服器端執行
當我們在客戶端執行SQL語句時,客戶端會把這條SQL語句發送給伺服器端,讓伺服器端的進程來處理這語句。也就是說,Oracle 客戶端是不會做任何的操作,他的主要任務就是把客戶端產生的一些SQL語句發送給伺服器端。伺服器進程從用戶進程把信息接收到後, 在PGA 中就要此進程分配所需內存,存儲相關的信息,如:在會話內存存儲相關的登錄信息等。
雖然在客戶端也有一個資料庫進程,但是,這個進程的作用跟伺服器上的進程作用是不相同的,伺服器上的資料庫進程才會對SQL 語句進行相關的處理。不過,有個問題需要說明,就是客戶端的進程跟伺服器的進程是一一對應的。也就是說,在客戶端連接上伺服器後,在客戶端與伺服器端都會形成一個進程,客戶端上的我們叫做客戶端進程,而伺服器上的我們叫做伺服器進程。
第二步:語句解析
當客戶端把SQL語句傳送到伺服器後,伺服器進程會對該語句進行解析。這個解析的工作是在伺服器端所進行的,解析動作又可分為很多小動作。
1)查詢高速緩存(library cache)
伺服器進程在接到客戶端傳送過來的SQL語句時,不會直接去資料庫查詢。伺服器進程把這個SQL語句的字元轉化為ASCII等效數字碼,接著這個ASCII碼被傳遞給一個HASH函數,並返回一個hash值,然後伺服器進程將到shared pool中的library cache(高速緩存)中去查找是否存在相同的hash值。如果存在,伺服器進程將使用這條語句已高速緩存在SHARED POOL的library cache中的已分析過的版本來執行,省去後續的解析工作,這便是軟解析。若調整緩存中不存在,則需要進行後面的步驟,這便是硬解析。硬解析通常是昂貴的操作,大約占整個SQL執行的70%左右的時間,硬解析會生成執行樹,執行計劃,等等。
所以,採用高速數據緩存的話,可以提高SQL 語句的查詢效率。其原因有兩方面:一方面是從內存中讀取數據要比從硬碟中的數據文件中讀取數據效率要高,另一方面也是因為避免語句解析而節省了時間。
不過這里要注意一點,這個數據緩存跟有些客戶端軟體的數據緩存是兩碼事。有些客戶端軟體為了提高查詢效率,會在應用軟體的客戶端設置數據緩存。由於這些數據緩存的存在,可以提高客戶端應用軟體的查詢效率。但是,若其他人在伺服器進行了相關的修改,由於應用軟體數據緩存的存在,導致修改的數據不能及時反映到客戶端上。從這也可以看出,應用軟體的數據緩存跟資料庫伺服器的高速數據緩存不是一碼事。
2)語句合法性檢查(data dict cache)
當在高速緩存中找不到對應的SQL語句時,則伺服器進程就會開始檢查這條語句的合法性。這里主要是對SQL語句的語法進行檢查,看看其是否合乎語法規則。如果伺服器進程認為這條SQL語句不符合語法規則的時候,就會把這個錯誤信息反饋給客戶端。在這個語法檢查的過程中,不會對SQL語句中所包含的表名、列名等等進行檢查,只是檢查語法。
3)語言含義檢查(data dict cache)
若SQL 語句符合語法上的定義的話,則伺服器進程接下去會對語句中涉及的表、索引、視圖等對象進行解析,並對照數據字典檢查這些對象的名稱以及相關結構,看看這些欄位、表、視圖等是否在資料庫中。如果表名與列名不準確的話,則資料庫會就會反饋錯誤信息給客戶端。
所以,有時候我們寫select語句的時候,若語法與表名或者列名同時寫錯的話,則系統是先提示說語法錯誤,等到語法完全正確後再提示說列名或表名錯誤。
4)獲得對象解析鎖(control structer)
當語法、語義都正確後,系統就會對我們需要查詢的對象加鎖。這主要是為了保障數據的一致性,防止我們在查詢的過程中,其他用戶對這個對象的結構發生改變。
5)數據訪問許可權的核對(data dict cache)
當語法、語義通過檢查之後,客戶端還不一定能夠取得數據,伺服器進程還會檢查連接用戶是否有這個數據訪問的許可權。若用戶不具有數據訪問許可權的話,則客戶端就不能夠取得這些數據。要注意的是資料庫伺服器進程先檢查語法與語義,然後才會檢查訪問許可權。
6)確定最佳執行計劃
當語法與語義都沒有問題許可權也匹配,伺服器進程還是不會直接對資料庫文件進行查詢。伺服器進程會根據一定的規則,對這條語句進行優化。在執行計劃開發之前會有一步查詢轉換,如:視圖合並、子查詢解嵌套、謂語前推及物化視圖重寫查詢等。為了確定採用哪個執行計劃,Oracle還需要收集統計信息確定表的訪問聯結方法等,最終確定可能的最低成本的執行計劃。
不過要注意,這個優化是有限的。一般在應用軟體開發的過程中,需要對資料庫的sql語句進行優化,這個優化的作用要大大地大於伺服器進程的自我優化。
當伺服器進程的優化器確定這條查詢語句的最佳執行計劃後, 就會將這條SQL語句與執行計劃保存到數據高速緩存(library cache)。如此,等以後還有這個查詢時,就會省略以上的語法、語義與許可權檢查的步驟,而直接執行SQL語句,提高SQL語句處理效率。
第三步:綁定變數賦值
如果SQL語句中使用了綁定變數,掃描綁定變數的聲明,給綁定變數賦值,將變數值帶入執行計劃。若在解析的第一個步驟,SQL在高速緩沖中存在,則直接跳到該步驟。
第四步:語句執行
語句解析只是對SQL語句的語法進行解析,以確保伺服器能夠知道這條語句到底表達的是什麼意思。等到語句解析完成之後,資料庫伺服器進程才會真正的執行這條SQL語句。
對於SELECT語句:
1)首先伺服器進程要判斷所需數據是否在db buffer存在,如果存在且可用,則直接獲取該數據而不是從資料庫文件中去查詢數據,同時根據LRU 演算法增加其訪問計數;
2)若數據不在緩沖區中,則伺服器進程將從資料庫文件中查詢相關數據,並把這些數據放入到數據緩沖區中(buffer cache)。
其中,若數據存在於db buffer,其可用性檢查方式為:查看db buffer塊的頭部是否有事務,如果有事務,則從回滾段中讀取數據;如果沒有事務,則比較select的scn和db buffer塊頭部的scn,如果前者小於後者,仍然要從回滾段中讀取數據;如果前者大於後者,說明這是一非臟緩存,可以直接讀取這個db buffer塊的中內容。
對於DML語句(insert、delete、update):
1)檢查所需的資料庫是否已經被讀取到緩沖區緩存中。如果已經存在緩沖區緩存,則直接執行步驟3;
2)若所需的資料庫並不在緩沖區緩存中,則伺服器將數據塊從數據文件讀取到緩沖區緩存中;
3)對想要修改的表取得的數據行鎖定(Row Exclusive Lock),之後對所需要修改的數據行取得獨占鎖;
4)將數據的Redo記錄復制到redo log buffer;
5)產生數據修改的undo數據;
6)修改db buffer;
7)dbwr將修改寫入數據文件;
其中,第2步,伺服器將數據從數據文件讀取到db buffer經經歷以下步驟:
1)首先伺服器進程將在表頭部請求TM鎖(保證此事務執行過程其他用戶不能修改表的結構),如果成功加TM鎖,再請求一些行級鎖(TX鎖),如果TM、TX鎖都成功加鎖,那麼才開始從數據文件讀數據。
2)在讀數據之前,要先為讀取的文件准備好buffer空間。伺服器進程需要掃描LRU list尋找free db buffer,掃描的過程中,伺服器進程會把發現的所有已經被修改過的db buffer注冊到dirty list中。如果free db buffer及非臟數據塊緩沖區不足時,會觸發dbwr將dirty buffer中指向的緩沖塊寫入數據文件,並且清洗掉這些緩沖區來騰出空間緩沖新讀入的數據。
3)找到了足夠的空閑buffer,伺服器進程將從數據文件中讀入這些行所在的每一個數據塊(db block)(DB BLOCK是ORACLE的最小操作單元,即使你想要的數據只是DB BLOCK中很多行中的一行或幾行,ORACLE也會把這個DB BLOCK中的所有行都讀入Oracle DB BUFFER中)放入db buffer的空閑的區域或者覆蓋已被擠出LRU list的非臟數據塊緩沖區,並且排列在LRU列表的頭部,也就是在數據塊放入db buffer之前也是要先申請db buffer中的鎖存器,成功加鎖後,才能讀數據到db buffer。
若數據塊已經存在於db buffer cache(有時也稱db buffer或db cache),即使在db buffer中找到一個沒有事務,而且SCN比自己小的非臟緩存數據塊,伺服器進程仍然要到表的頭部對這條記錄申請加鎖,加鎖成功才能進行後續動作,如果不成功,則要等待前面的進程解鎖後才能進行動作(這個時候阻塞是tx鎖阻塞)。
在記redo日誌時,其具體步驟如下:
1)數據被讀入到db buffer後,伺服器進程將該語句所影響的並被讀入db buffer中的這些行數據的rowid及要更新的原值和新值及scn等信息從PGA逐條的寫入redo log buffer中。在寫入redo log buffer之前也要事先請求redo log buffer的鎖存器,成功加鎖後才開始寫入。
2)當寫入達到redo log buffer大小的三分之一或寫入量達到1M或超過三秒後或發生檢查點時或者dbwr之前發生,都會觸發lgwr進程把redo log buffer的數據寫入磁碟上的redo file文件中(這個時候會產生log file sync等待事件)。
3)已經被寫入redo file的redo log buffer所持有的鎖存器會被釋放,並可被後來的寫入信息覆蓋,redo log buffer是循環使用的。Redo file也是循環使用的,當一個redo file寫滿後,lgwr進程會自動切換到下一redo file(這個時候可能出現log file switch(check point complete)等待事件)。如果是歸檔模式,歸檔進程還要將前一個寫滿的redo file文件的內容寫到歸檔日誌文件中(這個時候可能出現log file switch(archiving needed)。
在為事務建立undo信息時,其具體步驟如下:
1)在完成本事務所有相關的redo log buffer之後,伺服器進程開始改寫這個db buffer的塊頭部事務列表並寫入scn(一開始scn是寫在redo log buffer中的,並未寫在db buffer)。
2)然後包含這個塊的頭部事務列表及scn信息的數據副本放入回滾段中,將這時回滾段中的信息稱為數據塊的「前映像」,這個「前映像」用於以後的回滾、恢復和一致性讀。(回滾段可以存儲在專門的回滾表空間中,這個表空間由一個或多個物理文件組成,並專用於回滾表空間,回滾段也可在其它表空間中的數據文件中開辟)。
在修改信息寫入數據文件時,其具體步驟如下:
1)改寫db buffer塊的數據內容,並在塊的頭部寫入回滾段的地址。
2)將db buffer指針放入dirty list。如果一個行數據多次update而未commit,則在回滾段中將會有多個「前映像」,除了第一個「前映像」含有scn信息外,其他每個"前映像"的頭部都有scn信息和"前前映像"回滾段地址。一個update只對應一個scn,然後伺服器進程將在dirty list中建立一條指向此db buffer塊的指針(方便dbwr進程可以找到dirty list的db buffer數據塊並寫入數據文件中)。接著伺服器進程會從數據文件中繼續讀入第二個數據塊,重復前一數據塊的動作,數據塊的讀入、記日誌、建立回滾段、修改數據塊、放入dirty list。
3)當dirty queue的長度達到閥值(一般是25%),伺服器進程將通知dbwr把臟數據寫出,就是釋放db buffer上的鎖存器,騰出更多的free db buffer。前面一直都是在說明oracle一次讀一個數據塊,其實oracle可以一次讀入多個數據塊(db_file_multiblock_read_count來設置一次讀入塊的個數)
當執行commit時,具體步驟如下:
1)commit觸發lgwr進程,但不強制dbwr立即釋放所有相應db buffer塊的鎖。也就是說有可能雖然已經commit了,但在隨後的一段時間內dbwr還在寫這條sql語句所涉及的數據塊。表頭部的行鎖並不在commit之後立即釋放,而是要等dbwr進程完成之後才釋放,這就可能會出現一個用戶請求另一用戶已經commit的資源不成功的現象。
2)從Commit和dbwr進程結束之間的時間很短,如果恰巧在commit之後,dbwr未結束之前斷電,因為commit之後的數據已經屬於數據文件的內容,但這部分文件沒有完全寫入到數據文件中。所以需要前滾。由於commit已經觸發lgwr,這些所有未來得及寫入數據文件的更改會在實例重啟後,由smon進程根據重做日誌文件來前滾,完成之前commit未完成的工作(即把更改寫入數據文件)。
3)如果未commit就斷電了,因為數據已經在db buffer更改了,沒有commit,說明這部分數據不屬於數據文件。由於dbwr之前觸發lgwr也就是只要數據更改,(肯定要先有log)所有dbwr在數據文件上的修改都會被先一步記入重做日誌文件,實例重啟後,SMON進程再根據重做日誌文件來回滾。
其實smon的前滾回滾是根據檢查點來完成的,當一個全部檢查點發生的時候,首先讓LGWR進程將redologbuffer中的所有緩沖(包含未提交的重做信息)寫入重做日誌文件,然後讓dbwr進程將dbbuffer已提交的緩沖寫入數據文件(不強制寫未提交的)。然後更新控制文件和數據文件頭部的SCN,表明當前資料庫是一致的,在相鄰的兩個檢查點之間有很多事務,有提交和未提交的。
當執行rollback時,具體步驟如下:
伺服器進程會根據數據文件塊和db buffer中塊的頭部的事務列表和SCN以及回滾段地址找到回滾段中相應的修改前的副本,並且用這些原值來還原當前數據文件中已修改但未提交的改變。如果有多個」前映像「,伺服器進程會在一個「前映像」的頭部找到「前前映像」的回滾段地址,一直找到同一事務下的最早的一個「前映像」為止。一旦發出了commit,用戶就不能rollback,這使得commit後dbwr進程還沒有全部完成的後續動作得到了保障。
第五步:提取數據
當語句執行完成之後,查詢到的數據還是在伺服器進程中,還沒有被傳送到客戶端的用戶進程。所以,在伺服器端的進程中,有一個專門負責數據提取的一段代碼。他的作用就是把查詢到的數據結果返回給用戶端進程,從而完成整個查詢動作。
從這整個查詢處理過程中,我們在資料庫開發或者應用軟體開發過程中,需要注意以下幾點:
一是要了解資料庫緩存跟應用軟體緩存是兩碼事情。資料庫緩存只有在資料庫伺服器端才存在,在客戶端是不存在的。只有如此,才能夠保證資料庫緩存中的內容跟資料庫文件的內容一致。才能夠根據相關的規則,防止數據臟讀、錯讀的發生。而應用軟體所涉及的數據緩存,由於跟資料庫緩存不是一碼事情,所以,應用軟體的數據緩存雖然可以提高數據的查詢效率,但是,卻打破了數據一致性的要求,有時候會發生臟讀、錯讀等情況的發生。所以,有時候,在應用軟體上有專門一個功能,用來在必要的時候清除數據緩存。不過,這個數據緩存的清除,也只是清除本機上的數據緩存,或者說,只是清除這個應用程序的數據緩存,而不會清除資料庫的數據緩存。
二是絕大部分SQL語句都是按照這個處理過程處理的。我們DBA或者基於Oracle資料庫的開發人員了解這些語句的處理過程,對於我們進行涉及到SQL語句的開發與調試,是非常有幫助的。有時候,掌握這些處理原則,可以減少我們排錯的時間。特別要注意,資料庫是把數據查詢許可權的審查放在語法語義的後面進行檢查的。所以,有時會若光用資料庫的許可權控制原則,可能還不能滿足應用軟體許可權控制的需要。此時,就需要應用軟體的前台設置,實現許可權管理的要求。而且,有時應用資料庫的許可權管理,也有點顯得繁瑣,會增加伺服器處理的工作量。因此,對於記錄、欄位等的查詢許可權控制,大部分程序涉及人員喜歡在應用程序中實現,而不是在資料庫上實現。
Oracle SQL語句執行順序
(8)SELECT (9) DISTINCT (11) <select_list>
(1) FROM <left_table>
(3) <join_type> JOIN <right_table>
(2) ON <join_condition>
(4) WHERE <where_condition>
(5) GROUP BY <group_by_list>
(6) WITH {CUBE | ROLLUP}
(7) HAVING <having_condition>
(10) ORDER BY <order_by_list>
1)FROM:對FROM子句中的表執行笛卡爾積(交叉聯接),生成虛擬表VT1。
2)ON:對VT1應用ON篩選器,只有那些使為真才被插入到TV2。
3)OUTER (JOIN):如果指定了OUTER JOIN(相對於CROSS JOIN或INNER JOIN),保留表中未找到匹配的行將作為外部行添加到VT2,生成TV3。如果FROM子句包含兩個以上的表,則對上一個聯接生成的結果表和下一個表重復執行步驟1到步驟3,直到處理完所有的表位置。
4)WHERE:對TV3應用WHERE篩選器,只有使為true的行才插入TV4。
5)GROUP BY:按GROUP BY子句中的列列表對TV4中的行進行分組,生成TV5。
6)CUTE|ROLLUP:把超組插入VT5,生成VT6。
7)HAVING:對VT6應用HAVING篩選器,只有使為true的組插入到VT7。
8)SELECT:處理SELECT列表,產生VT8。
9)DISTINCT:將重復的行從VT8中刪除,產品VT9。
10)ORDER BY:將VT9中的行按ORDER BY子句中的列列表順序,生成一個游標(VC10),生成表TV11,並返回給調用者。
以上每個步驟都會產生一個虛擬表,該虛擬表被用作下一個步驟的輸入。這些虛擬表對調用者(客戶端應用程序或者外部查詢)不可用。只有最後一步生成的表才會會給調用者。如果沒有在查詢中指定某一個子句,將跳過相應的步驟。
4. 如何使用oracle提供的SQL
Sql性能非常差的時候,oracle提供了SQL_TRACE來跟蹤sql的執行情況。
註:分析sql的方式比較多,還有根據優化器、sql執行計劃來分析。
SQL_TRACE能夠將sql執行的過程輸出到一個trace文件裡面。
首先設置自己定義的trace文件的標識方便查找。
alter session set tracefile_identifier='mytest';
然後對當前會話啟動SQL_TRACE,最好不要一直打開該開關,代價比較大。
alter session set sql_trace=true;
然後我們執行一條sql語句。
最後關閉該開關的狀態。
alter session set sql_trace=false;
我們可以從目錄%ORACLE_BASE%/diag/rdbms/orcl/orcl/trace(11g版本的路徑,如果是10g的應該不一樣)中
找到自己定義的trace文件。
原始的trace文件的可讀性不高,我們一般使用oracle自帶的工具,tkprof來處理這個trace文件。我們可以查看tkprof的幫助。
tkprof orcl_ora_3820_mytest.trc out.txt
我們來看剛才生成的trace文件,頭部信息描述了tkprof 的版本以及報告中一些列的含義,對於任何一條sql語句,都應該包含Parse—sql分析階段,Execute—sql執行階段,Fetch—數據提取階段,橫向的列如圖所示,包含消耗cpu時間0.00秒,操作總耗時0.04秒,物理讀取了0個數據塊,沒有發生current方式的讀取(一般在update會發生),一共提取記錄1條。
Misses in library cache ring parse: 0表示這是一次軟分析(關於硬分析和軟分析下面會接著談到)
Optimizer mode: ALL_ROWS表示oracle的優化器模式為ALL_ROWS。這也就是前面提到的另外的分析方式優化器。
下面是sql執行的具體計劃,可以看到執行計劃選擇的是全表掃描。
經過處理以後的trace文件的確比較容易看明白,它有助於我們分析sql的性能問題。
下面我通過一個trace實例來解釋一下,為什麼OLTP系統中需要變數綁定機制。
當用戶和資料庫建立連接,並發送一條sql語句以後,oracle會對該sql進行hash函數運算(hash演算法提供了一種快速存取數據的方法,它用一種演算法建立鍵值與真實值之間的對應關系,每一個真實值只能有一個鍵值,但是一個鍵值可以對應多個真實值,以方便存取),得到一個hash值,然後到共享池中尋找是否有匹配的hash值的sql存在,如果有,就直接使用該sql的執行計劃去執行sql。如果沒有,oracle就會認為這是一條新的sql語句,然後按照語法分析,語義分析,生成執行計劃,執行sql這些步驟來執行最終把結果返回給用戶。這些步驟也被成為硬分析,可以想像,如果減少硬分析,能夠大大降低資料庫花費在sql解析上的資源開銷。
我們先執行一條sql 1000次,比較綁定變數和不綁定變數的差異。得到結果以後,要計算實際的消耗,我們需要把OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS以及OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS的時間累計起來,前者表示數據字典表的相關的信息,包含許可權控制等,後者表示sql所衍生出的遞歸sql語句的信息。可以看到綁定變數的,整條語句執行時間為0.22+0.02=0.24秒,CPU時間0.18+0.03=0.21秒,分析次數3次,執行次數1003次。而不綁定變數的時候,整條語句執行時間為0.28+1.29=1.57秒,CPU時間0.31+1.26=1.57秒,分析次數1002次,執行次數1003次。可見綁定變數的確能夠帶來更低的開銷。(如何設計資料庫中使用綁定變數也是和系統息息相關的,很多資料庫問題都是在設計以後就已經存在的)
應用級調優分析:
就通常所說的三層架構來說,中間件這一層能夠起到一個緩沖池的作用,如果並發用戶數到3000這個數量級的時候,中間件能夠控制不是所有的用戶都能直接連接到資料庫,當然這里的程序會快速響應用戶請求,保證緩沖池的隊列等待不會很久。
對應用這一級別的調優,主要集中在app程序,中間件的監控,集群配置等方面。如果是發現應用級別的問題,首先要分析是配置問題,還是程序本身的問題。如果並發用戶數很大,中間件的線程池最大值配置過小,會導致在請求隊列堆積,表現就是線程監控視圖中,請求的隊列堆積比較多,一般可以調整線程池最大值來解決。我們來看看weblogic的監控視圖。
考慮到如果為每一個請求都創建一個新線程來處理的話,那麼我們難以在系統中實現足夠數量的線程。不受限制的創建線程可能耗盡系統資源,因此引入了線程池。線程池的思想是在進程開始時創建一定數量的線程並將它們置入一個池(pool)中,線程在這個池中等待工作。當伺服器接收到一個請求時,它就從池中喚醒一個線程(如果有可用的線程),由它來處理請求。一旦線程服務完畢,它就返回線程池等待後面的工作。
線程池利用已存在的線程服務請求要比等待創建一個線程要快,並且線程池限制了線程的數量。
如果懷疑是程序的問題,我們一般可以通過java自帶的工具來幫助分析,工具很多。這里我主要提到一個jdk1.6以後附帶的jvisualvm。
我們打開jdk1.6,找到並運行jvisualvm.exe。
我們發現應用程序分為本地,遠程兩部分。本地包含本地運行的java進程,遠程能夠通過配置連接到遠程伺服器上的java進程。我們先啟動一個tomcat。可以看到本地應用程序已經打開了一個帶有tomcat以及進程標識id的菜單。雙擊打開。這里我們一般關心2個視圖。監視、線程。
其中監視視圖比較關心垃圾回收活動(顧名思義,回收那些在程序裡面不再使用到的內存空間),堆內存變化。如果在壓力測試過程中,堆內存變化是一個逐漸上漲的趨勢,並且經過多次手動gc回收,還是保持這個趨勢,說明內存泄漏的可能性很大。如果猜測有內存泄漏,可以通過分析java的heap mp。JVM (java虛擬機)記錄下問題發生時系統的運行狀態並將其存儲在轉儲(mp)文件中。Heap mp就是這樣一種文件形式。
線程視圖比較關心線程的當前執行狀態,這里可以生成另一種轉儲文件 Java mp。Java mp,也叫做 Thread mp,是 JVM 故障診斷中最重要的轉儲文件之一。JVM 的許多問題都可以使用這個文件進行診斷,其中比較典型的包括線程阻塞,CPU 使用率過高,JVM Crash,堆內存不足,和類裝載等問題。其中線程阻塞更加常見。
原文轉自:http://blog.csdn.net/xuyubotest/article/details/8158241
5. 求助,請問有類似SQL語義分析器的工具嗎
一般用oracle的都會用pl/sql 的工具
不過這個不是很好用。
強烈的推薦一款軟體。。SqlDBX。一般的資料庫都可以用oracle,serversql,mysql等。。
你可以試試。。
6. 如何獲取SQL2005下的SQL語句的語義分析
我想獲取一段sql語句在 mssql2005下解析成的語句,
主要是想獲取這個sql所用到的所有的表的名字。(ps:復雜的sql語句的)
請高手幫忙 在線等~
我的意思是要從用戶輸入的sql語句中提取該語句中所用的表
或者是:
sql 執行的步驟
1. 解析器
第 1 階段是解析器階段,它將 SQL 文本轉換成語法樹。這個階段不查找系統目錄中的任何信息,不訪問資料庫。
2. 語義分析
第 2 階段分析由解析器創建的語法樹,並產生用於查詢的查詢控制塊和表達式樹。要構建這些內部數據結構,它執行以下操作:
驗證對象
解析 UDR
如果可能的話,消除常量
驗證對象
第 2 階段訪問資料庫中不同的系統目錄,以驗證查詢所引用的所有資料庫對象(諸如表、列、視圖、類型、UDR 等等)是否都存在。它在資料庫中找到這些對象的標識,然後創建查詢控制塊和表達式樹。
我要的就是驗證對象步驟里的表的信息
7. PostgreSQL查詢SQL語義分析(1)—解析查詢對象addRangeTableEntry
本文主要介紹PG在執行查詢時,對SQL的語義分析重寫過程中的查詢對象解析過程,處理的函數為addRangeTableEntry,分析查詢對象信息。
本函數是解析查詢 (包含增刪改查操作) 執行過程中涉及的查詢對象 (表、視圖、子查詢等) 的信息。
每次調用只解析一個對象。
1、通過觀察addRangeTableEntry的執行過程,了解SQL語義解析transformFromClause的處理過程。
2、表結構信是從緩存中結構讀取,然後獲取自己需要的信息。
3、語義分析後轉換為relid(關聯對象id),提升查詢執行的處理效率。
8. 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 演算法。
9. 將MySQL資料庫移植為PostgreSQL
在北美,人們對於
PostgreSQL
的熱情不斷升溫。隨著
PostgreSQL
的發展,
PostgreSQL
8.x
已經從技術上超越
MySQL
5.x
,而市場的超越相信只是時間問題。而最終,用戶也許有機會享受到可媲美
Oracle
的開源資料庫也未嘗沒有可能。
我供職的互聯網公司,服務約
50
萬商務用戶,經過多次的升級移植,目前公司已經全部將後台資料庫從
MySQL
移植到
PostgreSQL
,而個人完成了其中一半的資料庫移植工作,所以對資料庫從
MySQL
移植到
PostgreSQL
積累了一些經驗。在此整理成文,希望能對大家使用
PostgreSQL
有一些啟發。
1)
准備:
使用
MySQL
數據備份工具對資料庫進行全備份:
mysqlmp
-h
[hostname]
-u
[username]
-p
[password]
--extended-insert=false
[dbname]
>
mysql-db.sql
注意
disable
extended-insert
,
PostgreSQL
不支持
MySQL
的
extended-insert
2)
轉化:
將
mysql-db.sql
轉為
PostgreSQL
可以導入的
SQL
Script.
MySQL
和
PostgreSQL
在
SQL
語義上存在一定差異,比如
MySQL
不支持
sequence
,觸發器等功能,但為此又提供了一些自有的語法規則,而對比一些系統函數,
MySQL
和
PostgreSQL
又存在比較大的差別。為此,我編寫了一段語義分析和轉化的程序
mysql2psql
>mysql2psql
mysql-db.sql
postgres-db.sql
3)
導入:
使用
PostgreSQL
提供的
pgAdmin
將數據文件導入資料庫。
4)
SQL
語句的修改:
在實際的應用中,前端的系統往往會嵌入一些具有資料庫特性的
SQL
語句,而隨著後台資料庫的改變,前端的系統程序也同樣需要做出相應的修改。
MySQL
和
PostgreSQL
最常見的不同之處包括:Group
by,Join的使用差異,系統函數的命名和調用的差異等等。
10. 什麼是sql注入如何防止sql注入
SQL注入是一種非常常見的資料庫攻擊手段,同時也是網路世界中最普遍的漏洞之一,簡單理解就是惡意用戶通過在表單中填寫包含SQL關鍵字的數據來使資料庫執行非常規代碼的過程。
問題來源是,SQL資料庫的操作是通過SQL語句來執行的,而無論是執行代碼還是數據項都必須寫在SQL語句中,也就導致如果我們在數據項中加入了某些SQL語句關鍵字,比如SELECT、DROP等,這些關鍵字就很有可能在資料庫寫入或讀取數據時得到執行。
解決方案
方案一:
採用預編譯技術
使用預編譯的SQL語句,SQL語句的語義不會是不會發生改變的。預編譯語句在創建的時候就已經將指定的SQL語句發送給了DBMS,完成了解析,檢查,編譯等工作,所以攻擊者無法改變SQL語句的結構,只是把值賦給?,然後將?這個變數傳給SQL語句。當然還有一些通過預編譯繞過某些安全防護的操作,大家感興趣可以去搜索一下。
方案二:
嚴格控制數據類型
在java、c等強類型語言中一般是不存在數字型注入的,因為在接受到用戶輸入id時,代碼一般會做一個int id 的數據類型轉換,假如我們輸入的是字元串的話,那麼這種情況下,程序就會報錯。但是在PHP、ASP這些沒有強調處理數據類型的語言,一般我們看到的接收id的代碼都是如下等代碼。
方案三:
對特殊的字元進行轉義
數字型注入可以通過檢查數據類型防止,但是字元型不可以,那麼怎麼辦呢,最好的辦法就是對特殊的字元進行轉義了。比如在MySQL中我們可以對" '
"進行轉義,這樣就防止了一些惡意攻擊者來閉合語句。當然我們也可以通過一些安全函數來轉義特殊字元。如addslashes()等,但是這些函數並非一勞永逸,攻擊者還可以通過一些特殊的方式繞過。