圖資料庫測試
㈠ 關於資料庫的問題,畫ERD圖
分析3.1】 重點:軟體開發方法、CMM、成本估算、風險分析、進度管理、人員管理、軟體開發環境 3.2 系統分析基礎知識 · 系統分析的目的和任務 · 結構化分析方法(數據流圖(DFD)、數據字典(DD)、實體關系圖(ERD)、描述加工處理的結構化語言) · 統一建模語言(UML) · 系統規格說明書 【分析3.2】 高度重視UML在系統分析中的應用 重點:數據流圖(DFD)、數據字典(DD)、實體關系圖(ERD) 考點:UML的各類圖 3.3 系統設計知識 · 系統設計的目的和任務 · 結構化設計方法和工具(系統流程圖、HIPO圖、控制流程圖) · 系統總體結構設計(總體布局、設計原則、模塊結構設計、數據存儲設計、系統配置方案) · 系統詳細設計(代碼設計、資料庫設計、用戶界面設計、處理過程設計) · 系統設計說明書 【分析3.3】 重點:系統流程圖、HIPO圖、控制流程圖 3.4 系統實施知識 · 系統實施的主要任務 · 結構化程序設計、面向對象程序設計、可視化程序設計 · 程序設計風格 · 程序設計語言的選擇 · 系統測試的目的、類型,系統測試方法(黑盒測試、白盒測試、灰盒測試) · 測試設計和管理(錯誤曲線、錯誤排除、收斂、注入故障、測試用例設計、系統測試報告) · 系統轉換基礎知識 3.5 系統運行和維護知識 · 系統運行管理基礎知識 · 系統維護基礎知識 · 系統評價基礎知識 【分析3.4/3.5】 重點:結構化設計中信息流、變換分析、系統結構設計原則、系統劃分、模塊設計、數據存儲設計、面向對象程序設計、測試方法、系統維護的分類 難點:系統測試方法、測試分類、系統可維護性評價指標 3.6 面向對象開發方法 · 面向對象開發概念(類、對象、屬性、封裝性、繼承性、多態性、對象之間的引用) · 面向對象開發方法的優越性以及有效領域 · 面向對象設計方法(體系結構、類的設計、用戶介面設計) · 面向對象實現方法(選擇程序設計語言、類的實現、方法的實現、用戶介面的實現、准備測試數據) · 面向對象程序設計語言(如C++、Java、Visual、Bsasic、Visual C++)的基本機制 · 面向對象資料庫、分布式對象的概念 【分析3.6】 重點:面向對象開發:類、對象、屬性、封裝性、繼承性、多態性、OMT方法 難點:建議在數據流圖、結構化分析方法上多加掌握。 【分析3】 考試題型一般分布在:DFD、軟體的生存周期;數據流圖;模塊間的關系;軟體測試的分類、軟體質量管理(標准)軟體的特性、主要的軟體開發方法、系統測試、軟體能力成熟評估 考試出現頻率較高的內容:數據流圖、黑盒/白盒測試、面向對象技術的概念 4.安全性知識 · 安全性基本概念 · 防治計算機病毒、防範計算機犯罪 · 存取控制、防闖入、安全管理措施 · 加密與解密機制 · 風險分析、風險類型、抗風險措施和內部控制 【分析4】 系統安全問題是目前社會關注的問題,也是應用價值較高的知識,可結合現實中的相關問題來加深理解。 考試出現頻率較高的內容:加密與解密演算法、 5.標准化知識 · 標准化意識、標准化的發展、標准制訂過程 · 國際標准、國家標准、行業標准、企業標准基本知識 · 代碼標准、文件格式標准、安全標准、軟體開發規范和文檔標准知識 · 標准化機構 6.信息化基礎知識 · 信息化意識 · 全球信息化趨勢、國家信息化戰略、企業信息化戰略和策略 · 有關的法律、法規 · 遠程教育、電子商務、電子政務等基礎知識 · 企業信息資源管理基礎知識 【分析5/6】 信息化、標准化知識是新增考點。標准化方面有標准標識,標准修訂等是對基本素質的考查,也要重視。 考試出現頻率較高的內容 7.計算機專業英語 · 掌握計算機技術的基本詞彙 · 能正確閱讀和理解計算機領域的英文資料 【分析7】 專業英語,是對專業知識和英語水平的考查,考前需有意識閱讀點英文專業資料。 考試題型一般分布在:軟體行業標准,計算機安全基礎知識,信息化基礎知識。 考試出現頻率較高的內容:行業標準的類別;計算機安全,CMM分類,計算機軟體著作權問題。 考試科目2:軟體設計 本部分具體內容如下: l 外部設計 l 內部設計 l 程序設計 l 系統實施 l 軟體工程 本部分所涉及內容為軟體設計的日常工作,這些內容同樣出現在上午考試試題中。 1.外部設計 1.1 理解系統需求說明 1.2 系統開發的准備 · 選擇開發方法、准備開發環境、制訂開發計劃 1.3 設計系統功能 · 選擇系統結構,設計各子系統的功能和介面,設計安全性策略、需求和實現方法,制訂詳細的工作流和數據流 1.4 設計數據模型 · 設計ER模型、數據模型 1.5 編寫外部設計文檔 · 系統配置圖、各子系統關系圖、系統流程圖、系統功能說明書、輸入輸出規格說明、數據規格說明、用戶手冊框架 · 設計系統測試要求 1.6 設計評審 應能由考試說明內容,來閱讀 2.內部設計 2.1 設計軟體結構 · 按構件分解,確定構件功能規格以及構件之間的介面 · 採用中間件和工具 2.2 設計輸入輸出 · 屏幕界面設計、設計輸入輸出檢查方法和檢查信息 2.3 設計物理數據 · 分析數據特性,確定邏輯數據組織方式、存儲介質,設計記錄格式和處理方式 · 將邏輯數據結構換成物理數據結構,計算容量,進行優化 2.4 構件的創建和重用 · 創建、重用構件的概念 · 使用子程序庫或類庫 2.5 編寫內部設計文檔 · 構件劃分圖、構件間的介面、構件處理說明、屏幕設計文檔、報表設計文檔、文件設計文檔、資料庫設計文檔 2.6 設計評審 3.程序設計 3.1 模塊劃分(原則、方法、標准) 3.2 編寫程序設計文檔 · 模塊規格說明書(功能和介面說明、程序處理邏輯的描述、輸入輸出數據格式的描述) · 測試要求說明書(測試類型和目標、測試用例、測試方法) 3.3 程序設計評審 4.系統實施 4.1 配置計算機系統及其環境 4.2 選擇合適的程序設計語言 4.3 掌握C程序設計語言,以及C++、Java、Visual Basic、Visual C++中任一種程序設計語言,以便能指導程序員進行編程和測試,並進行必要的優化 4.4 系統測試 · 指導程序員進行模塊測試,並進行驗收 · 准備系統集成測試環境和測試工具 · 准備測試數據 · 寫出測試報告 5.軟體工程 · 軟體生存期模型(瀑布模型、螺旋模型、噴泉模型)和軟體成本模型 · 定義軟體需求(系統化的目標、配置、功能、性能和約束) · 描述軟體需求的方法(功能層次模型、數據流模型、控制流模型、面向數據的模型、面向對象的模型等) · 定義軟體需求的方法(結構化分析方法、面向對象分析方法) · 軟體設計(分析與集成、逐步求精、抽象、信息隱蔽) · 軟體設計方法(結構化設計方法、Jackson方法、Warnier方法、面向對象設計方法) · 程序設計(結構化程序設計、面向對象程序設計) · 軟體測試的原則與方法 · 軟體質量(軟體質量特性、軟體質量控制) · 軟體過程評估基本方法、軟體能力成熟度評估基本方法 · 軟體開發環境和開發工具(分析工具、設計工具、編程工具、測試工具、維護工具、CASE) · 軟體工程發展趨勢(面向構件,統一建模語言(UML)) · 軟體過程改進模型和方法 本部分綜合分析: 軟體設計師,關鍵是設計軟體的能力。考綱要求:要熟悉軟體工程、軟體過程改進和軟體開發項目管理的基礎知識;熟練掌握軟體設計的方法和技術;掌握C程序設計語言及指定的四種面向對象語言中的一種。這部分專業能力嚴重依賴工作實踐,要求有一定經驗的積累,是具有工程師的實際工作能力和業務水平的體現。如無實踐經驗,要學會借鑒,以取人之長,補已之短。 這部分主要體現在下午考試中,現就如何應對下午考試進行分析: 近幾次考試中下午試題分五個題目,一個資料庫,一個程序填空題、一個面向對象的語言題,另兩個題目分別為數據流圖、UML、或流程圖等。 資料庫題目,要求補全sql語言,這要求考生熟悉SQL的語言,無論對上午題目還是下午題目都很重要。這是學習和復習的一個重點。 數據流圖,DFD是一種分析系統數據流程的圖形,意在讓用戶理解系統的功能、輸入、輸出和數據存儲等。請認真弄清其應用,在畫出數據流圖的情況下,系統的功能也就確定了,再經過細化,逐步向物理結構邁進。考核時,試題多從父圖和子圖的平衡來分析。這部分內容,一個解題的關鍵是高度重視題目說明,務必正確、深入理解其內容,必要時要讀幾遍,同時對於給出的圖表,也要務必看懂。這樣答題就輕鬆了,答案實際就蘊含在說明中。 流程圖類題目,是大家再熟悉不過的了,它就一個具體問題的解題思路進行描述,是面向過程的。但所求問題是千差萬別的,因此應理解思路,細心作答。 答題形式最簡單也是難度最大的是程序填空。為便於閱卷,這類題目以程序填空形式出現,這不僅要求理解問題本質,同時也要弄清作者解題思路,這一點比自己獨立完成程序設計要難得的多。針對問題,首先設計自己的思路,如何解決問題,先後順序怎樣;然後試讀程序,如何思路大體一致,很好,這題容易解決了。如思路不一致,設法弄清每一段代碼的功能,其邏輯結構怎樣,進而弄清命題人的解題思路,再順勢解決問題。人們常講,答案就在題目中,這是對的。在分析問題過程中,找到所求答案。不過前提條件是考生要熟悉這種語言,又要明白解題思路,這樣才能正確作答。這個題目比較難,要麼不得分,要麼得全分。 近年對於統一建模語言UML考查較多,已引起了考生的注意。它代表了軟體工程的發展趨勢,目前是可視化建模的事實上的工業標准。人們對於圖的理解相對其他形式更容易一些,圖能更清晰地描述和說明問題的本質,因此,UML體現了這一特點。這類題目難度與數據流圖相似,自然解題思想也相同。從形式上看,數據流圖更朴實一些,UML類的題目則透出一種新穎、現代的氣息。 最後的題目面向對象語言是一個選做題,給考生以自由,可以發揮個人的優勢。命題已注意到不同語言的考查難度一致性,要求考生就同一問題回答,實現了形式上的公平,自然是一個進步
㈡ 資料庫中視圖怎麼進行軟體測試
從測試過程的角度來說我們也可以把資料庫測試分為:
系統測試
傳統軟體系統測試的測試重點是需求覆蓋,而對於我們的資料庫測試同樣也需要對需求覆蓋進行保證。那麼資料庫在初期設計中也需要對這個進行分析,測試。例如存儲過程,視圖,觸發器,約束,規則等我們都需要進行需求的驗證確保這些功能設計是符合需求的.另一方面我們需要確認資料庫設計文檔和最終的資料庫相同,當設計文檔變化時我們同樣要驗證改修改是否落實到資料庫上。
這個階段我們的測試主要通過資料庫設計評審來實現。
集成測試
集成測試是主要針對介面進行的測試工作,從資料庫的角度來說和普通測試稍微有些區別對於資料庫測試來說,需要考慮的是數據項的修改操作、數據項的增加操作、數據項的刪除操作、數據表增加滿、數據表刪除空、刪除空表中的記錄、數據表的並發操作、針對存儲過程的介面測試、結合業務邏輯做關聯表的介面測試。
同樣我們需要對這些介面考慮採用等價類、邊界值、錯誤猜測等方法進行測試。
單元測試
單元測試側重於邏輯覆蓋,相對對於復雜的代碼來說,資料庫開發的單元測試相對簡單些,可以通過語句覆蓋和走讀的方式完成。
系統測試相對來說比較困難,這要求有很高的資料庫設計能力和豐富的資料庫測試經驗。而集成測試和單元測試就相對簡單了。
而我們也可以從測試關注點的角度對資料庫進行分類:
功能測試
對資料庫功能的測試我們可以依賴與工具進行:悉陸
DBunit:一款開源的資料庫功能測試框架,可以使用類似與Junit的方式對資料庫的基本操作進行白盒的單元測試,對輸入輸出進行校驗。
QTP:大名鼎鼎的自動測試工具,通過對對象的捕捉識別,我們可以通過QTP來模擬用戶的操作流程,通過其中的校驗方法或者結合資料庫後台的監控對整個資料庫中的數據進行測試。個人覺得比睜汪頃較偏向灰盒。
DataFactory:一款優秀的資料庫數據自動生成工具,通過它你可以輕松的生成任意結構資料庫,對資料庫進行填充,幫助你生成所需要的大量數據從而驗證我們資料庫中的功能是否正確。這是屬於黑盒測試。
資料庫性能雖然我們的硬體最近幾年進步很快,但是我們需要處理的數據以更快的速度在增加。幾億條記錄的表格在現在是司空見慣的,如此龐大的數據量在大量並發連接操作時,我們不能像以前一樣隨意的使用查詢,連接查詢,嵌套查詢,視圖,這陵橋些操作如果不當會給系統帶來非常巨大的壓力,嚴重影響系統性能。
性能優化分4部分:
1、物理存儲方面
2、邏輯設計方面
3、資料庫的參數調整
4、SQL語句優化
性能測試:
我們如何對性能方面進行測試呢,業界也提供了很多工具通過資料庫系統的SQL語句分析工具,我們可以分析得到資料庫語句執行的瓶頸,從而優化SQL語句。
Loadrunner:這個不用多說,我們可以通過對協議的編程來對資料庫做壓力測試。
Swingbench:(這是一個重量級別的feature,類似LR,而且非常強大,只不過專門針對oracle而已)資料庫廠商也意識到這點,例如oracle11g已經提供了real applicationtest,提供資料庫性能測試,分析系統的應用瓶頸。
還有很多第三方公司開發了SQL語句優化工具來幫助你自動的進行語句優化工作從而提高執行效率。
安全測試:
軟體日益復雜,而數據又成為了系統中重中之重的核心,從以往對系統的破壞現在更傾向於對數據的獲取和破壞。而資料庫的安全被提到了最前端自從SQL 注入攻擊被發現,冒失萬無一失的資料庫一下從後台變為了前台,而一旦資料庫被攻破,整個系統也會暴露在黑客的手下,通過資料庫強大的存儲過程,黑客可以輕松的獲得整個系統的許可權。而SQL的注入看似簡單缺很難防範,對於安全測試來說,如何防範系統被注入是測試的難點。
業界也有相關的資料庫注入檢測工具,來幫助用戶對自身系統進行安全檢測。
對於這點來說業界也有標准,例如ISO IEC 21827,也叫做SSE CMM 3.0,是CMM和ISO的集成的產物,專門針對系統安全領域的另外一方面,資料庫的健壯性,容錯性和恢復能力也是我們測試的要點
我們也可以發現功能測試,性能測試,安全測試,是一個由簡到繁的過程,也是資料庫測試人員需要逐步掌握的技能,這也是以後公司對資料庫測試人員的要求。
㈢ 怎麼測試資料庫的響應速度比如查詢速度
有很多種方法可以用來找出哪些SQL語句需要優化,但是很久以來,最簡單的方法都是分析保存在V$SQL視圖中的緩存的SQL信息。通過V$SQL視圖,可以確定具有高消耗時間、CUP和IO讀取的SQL語句。
1.查看總消耗時間最多的前10條SQL語句
select*
from(selectv.sql_id,
v.child_number,
v.sql_text,
v.elapsed_time,
v.cpu_time,
v.disk_reads,
rank()over(orderbyv.elapsed_timedesc)elapsed_rank
fromv$sqlv)a
whereelapsed_rank<=10;
2.查看CPU消耗時間最多的前10條SQL語句
select*
from(selectv.sql_id,
v.child_number,
v.sql_text,
v.elapsed_time,
v.cpu_time,
v.disk_reads,
rank()over(orderbyv.cpu_timedesc)elapsed_rank
fromv$sqlv)a
whereelapsed_rank<=10;
3.查看消耗磁碟讀取最多的前10條SQL語句
select*
from(selectv.sql_id,
v.child_number,
v.sql_text,
v.elapsed_time,
v.cpu_time,
v.disk_reads,
rank()over(orderbyv.disk_readsdesc)elapsed_rank
fromv$sqlv)a
whereelapsed_rank<=10;
㈣ 這個圖裡面硬碟有個存取測試,其中有512K有4K有64K,那麼用這些不同大小的文件做存儲測試是
一個1G的整文件 和 1G的碎小文件 讀取速度能一樣嗎? 1000個文件就要定址1000遍
測試不同大小文件 才能綜合測試一個硬碟的讀寫能力
特別是ssd 最重要的是4k的讀寫能力 因為系統文件全是小文件;誰沒事天天讀寫整個1g 2G的大文件呢
㈤ 如何用 Python 實現一個圖資料庫(Graph Database)
本文章是 重寫 500 Lines or Less 系列的其中一篇,目標是重寫 500 Lines or Less 系列的原有項目:Dagoba: an in-memory graph database。
Dagoba 是作者設計用來展示如何從零開始自己實現一個圖資料庫( Graph Database )。該名字似乎來源於作者喜歡的一個樂隊,另一個原因是它的前綴 DAG 也正好是有向無環圖 ( Directed Acyclic Graph ) 的縮寫。本文也沿用了該名稱。
圖是一種常見的數據結構,它將信息描述為若干獨立的節點( vertex ,為了和下文的邊更加對稱,本文中稱為 node ),以及把節點關聯起來的邊( edge )。我們熟悉的鏈表以及多種樹結構可以看作是符合特定規則的圖。圖在路徑選擇、推薦演算法以及神經網路等方面都是重要的核心數據結構。
既然圖的用途如此廣泛,一個重要的問題就是如何存儲它。如果在傳統的關系資料庫中存儲圖,很自然的做法就是為節點和邊各自創建一張表,並用外鍵把它們關聯起來。這樣的話,要查找某人所有的子女,就可以寫下類似下面的查詢:
還好,不算太復雜。但是如果要查找孫輩呢?那恐怕就要使用子查詢或者 CTE(Common Table Expression) 等特殊構造了。再往下想,曾孫輩又該怎麼查詢?孫媳婦呢?
這樣我們會意識到,SQL 作為查詢語言,它只是對二維數據表這種結構而設計的,用它去查詢圖的話非常笨拙,很快會變得極其復雜,也難以擴展。針對圖而言,我們希望有一種更為自然和直觀的查詢語法,類似這樣:
為了高效地存儲和查詢圖這種數據結構,圖資料庫( Graph Database )應運而生。因為和傳統的關系型資料庫存在極大的差異,所以它屬於新型資料庫也就是 NoSql 的一個分支(其他分支包括文檔資料庫、列資料庫等)。圖資料庫的主要代表包括 Neo4J 等。本文介紹的 Dagoba 則是具備圖資料庫核心功能、主要用於教學和演示的一個簡單的圖資料庫。
原文代碼是使用 JavaScript 編寫的,在定義調用介面時大量使用了原型( prototype )這種特有的語言構造。對於其他主流語言的用戶來說,原型的用法多少顯得有些別扭和不自然。
考慮到本系列其他資料庫示例大多是用 Python 實現的,本文也按照傳統,用 Python 重寫了原文的代碼。同樣延續之前的慣例,為了讓讀者更好地理解程序是如何逐步完善的,我們用迭代式的方法完成程序的各個組成部分。
原文在 500lines 系列的 Github 倉庫中只包含了實現代碼,並未包含測試。按照代碼注釋說明,測試程序位於作者的另一個代碼庫中,不過和 500lines 版本的實現似乎略有不同。
本文實現的代碼參考了原作者的測試內容,但跳過了北歐神話這個例子——我承認確實不熟悉這些神祇之間的親緣關系,相信中文背景的讀者們多數也未必了解,雖然作者很喜歡這個例子,想了想還是不要徒增困惑吧。因此本文在編寫測試用例時只參考了原文關於家族親屬的例子,放棄了神話相關的部分,盡管會減少一些趣味性,相信對於入門級的代碼來說這樣也夠用了。
本文實現程序位於代碼庫的 dagoba 目錄下。按照本系列程序的同意規則,要想直接執行各個已完成的步驟,讀者可以在根目錄下的 main.py 找到相應的代碼位置,取消注釋並運行即可。
本程序的所有步驟只需要 Python3 ,測試則使用內置的 unittest , 不需要額外的第三方庫。原則上 Python3.6 以上版本應該都可運行,但我只在 Python3.8.3 環境下完整測試過。
本文實現的程序從最簡單的案例開始,通過每個步驟逐步擴展,最終形成一個完整的程序。這些步驟包括:
接下來依次介紹各個步驟。
回想一下,圖資料庫就是一些點( node )和邊( edge )的集合。現在我們要做出的一個重大決策是如何對節點/邊進行建模。對於邊來說,必須指定它的關聯關系,也就是從哪個節點指向哪個節點。大多數情況下邊是有方向的——父子關系不指明方向可是要亂套的!
考慮到擴展性及通用性問題,我們可以把數據保存為字典( dict ),這樣可以方便地添加用戶需要的任何數據。某些數據是為資料庫內部管理而保留的,為了明確區分,可以這樣約定:以下劃線開頭的特殊欄位由資料庫內部維護,類似於私有成員,用戶不應該自己去修改它們。這也是 Python 社區普遍遵循的約定。
此外,節點和邊存在互相引用的關系。目前我們知道邊會引用到兩端的節點,後面還會看到,為了提高效率,節點也會引用到邊。如果僅僅在內存中維護它們的關系,那麼使用指針訪問是很直觀的,但資料庫必須考慮到序列化到磁碟的問題,這時指針就不再好用了。
為此,最好按照資料庫的一般要求,為每個節點維護一個主鍵( _id ),用主鍵來描述它們之間的關聯關系。
我們第一步要把資料庫的模型建立起來。為了測試目的,我們使用一個最簡單的資料庫模型,它只包含兩個節點和一條邊,如下所示:
按照 TDD 的原則,首先編寫測試:
與原文一樣,我們把資料庫管理介面命名為 Dagoba 。目前,能夠想到的最簡單的測試是確認節點和邊是否已經添加到資料庫中:
assert_item 是一個輔助方法,用於檢查字典是否包含預期的欄位。相信大家都能想到該如何實現,這里就不再列出了,讀者可參考 Github 上的完整源碼。
現在,測試是失敗的。用最簡單的辦法實現資料庫:
需要注意的是,不管添加節點還是查詢,程序都使用了拷貝後的數據副本,而不是直接使用原始數據。為什麼要這樣做?因為字典是可變的,用戶可以在任何時候修改其中的內容,如果資料庫不知道數據已經變化,就很容易發生難以追蹤的一致性問題,最糟糕的情況下會使得數據內容徹底混亂。
拷貝數據可以避免上述問題,代價則是需要佔用更多內存和處理時間。對於資料庫來說,通常查詢次數要遠遠多於修改,所以這個代價是可以接受的。
現在測試應該正常通過了。為了讓它更加完善,我們可以再測試一些邊緣情況,看看資料庫能否正確處理異常數據,比如:
例如,如果用戶嘗試添加重復主鍵,我們預期應拋出 ValueError 異常。因此編寫測試如下:
為了滿足以上測試,代碼需要稍作修改。特別是按照 id 查找主鍵是個常用操作,通過遍歷的方法效率太低了,最好是能夠通過主鍵直接訪問。因此在資料庫中再增加一個字典:
完整代碼請參考 Github 倉庫。
在上個步驟,我們在初始化資料庫時為節點明確指定了主鍵。按照資料庫設計的一般原則,主鍵最好是不具有業務含義的代理主鍵( Surrogate key ),用戶不應該關心它具體的值是什麼,因此讓資料庫去管理主鍵通常是更為合理的。當然,在部分場景下——比如導入外部數據——明確指定主鍵仍然是有用的。
為了同時支持這些要求,我們這樣約定:欄位 _id 表示節點的主鍵,如果用戶指定了該欄位,則使用用戶設置的值(當然,用戶有責任保證它們不會重復);否則,由資料庫自動為它分配一個主鍵。
如果主鍵是資料庫生成的,事先無法預知它的值是什麼,而邊( edge )必須指定它所指向的節點,因此必須在主鍵生成後才能添加。由於這個原因,在動態生成主鍵的情況下,資料庫的初始化會略微復雜一些。還是先寫一個測試:
為支持此功能,我們在資料庫中添加一個內部欄位 _next_id 用於生成主鍵,並讓 add_node 方法返回新生成的主鍵:
接下來,再確認一下邊是否可以正常訪問:
運行測試,一切正常。這個步驟很輕松地完成了,不過兩個測試( DbModelTest 和 PrimaryKeyTest )出現了一些重復代碼,比如 get_item 。我們可以把這些公用代碼提取出來。由於 get_item 內部調用了 TestCase.assertXXX 等方法,看起來應該使用繼承,但從 TestCase 派生基類容易引起一些潛在的問題,所以我轉而使用另一個技巧 Mixin :
實現資料庫模型之後,接下來就要考慮如何查詢它了。
在設計查詢時要考慮幾個問題。對於圖的訪問來說,幾乎總是由某個節點(或符合條件的某一類節點)開始,從與它相鄰的邊跳轉到其他節點,依次類推。所以鏈式調用對查詢來說是一種很自然的風格。舉例來說,要知道 Tom 的孫子養了幾只貓,可以使用類似這樣的查詢:
可以想像,以上每個方法都應該返回符合條件的節點集合。這種實現是很直觀的,不過存在一個潛在的問題:很多時候用戶只需要一小部分結果,如果它總是不計代價地給我們一個巨大的集合,會造成極大的浪費。比如以下查詢:
為了避免不必要的浪費,我們需要另外一種機制,也就是通常所稱的「懶式查詢」或「延遲查詢」。它的基本思想是,當我們調用查詢方法時,它只是把查詢條件記錄下來,而並不立即返回結果,直到明確調用某些方法時才真正去查詢資料庫。
如果讀者比較熟悉流行的 Python ORM,比如 SqlAlchemy 或者 Django ORM 的話,會知道它們幾乎都是懶式查詢的,要調用 list(result) 或者 result[0:10] 這樣的方法才能得到具體的查詢結果。
在 Dagoba 中把觸發查詢的方法定義為 run 。也就是說,以下查詢執行到 run 時才真正去查找數據:
和懶式查詢( Lazy Query )相對應的,直接返回結果的方法一般稱作主動查詢( Eager Query )。主動查詢和懶式查詢的內在查找邏輯基本上是相同的,區別只在於觸發機制不同。由於主動查詢實現起來更加簡單,出錯也更容易排查,因此我們先從主動查詢開始實現。
還是從測試開始。前面測試所用的簡單資料庫數據太少,難以滿足查詢要求,所以這一步先來創建一個更復雜的數據模型:
此關系的復雜之處之一在於反向關聯:如果 A 是 B 的哥哥,那麼 B 就是 A 的弟弟/妹妹,為了查詢到他們彼此之間的關系,正向關聯和反向關聯都需要存在,因此在初始化資料庫時需要定義的邊數量會很多。
當然,父子之間也存在反向關聯的問題,為了讓問題稍微簡化一些,我們目前只需要向下(子孫輩)查找,可以稍微減少一些關聯數量。
因此,我們定義數據模型如下。為了減少重復工作,我們通過 _backward 欄位定義反向關聯,而資料庫內部為了查詢方便,需要把它維護成兩條邊:
然後,測試一個最簡單的查詢,比如查找某人的所有孫輩:
這里 outcome/income 分別表示從某個節點出發、或到達它的節點集合。在原作者的代碼中把上述方法稱為 out/in 。當然這樣看起來更加簡潔,可惜的是 in 在 Python 中是個關鍵字,無法作為函數名。我也考慮過加個下劃線比如 out_.in_ 這種形式,但看起來也有點怪異,權衡之後還是使用了稍微啰嗦一點的名稱。
現在我們可以開始定義查詢介面了。在前面已經說過,我們計劃分別實現兩種查詢,包括主動查詢( Eager Query )以及延遲查詢( Lazy Query )。
它們的內在查詢邏輯是相通的,看起來似乎可以使用繼承。不過遵循 YAGNI 原則,目前先不這樣做,而是只定義兩個新類,在滿足測試的基礎上不斷擴展。以後我們會看到,與繼承相比,把共同的邏輯放到資料庫本身其實是更為合理的。
接下來實現訪問節點的方法。由於 EagerQuery 調用查詢方法會立即返回結果,我們把結果記錄在 _result 內部欄位中。雖然 node 方法只返回單個結果,但考慮到其他查詢方法幾乎都是返回集合,為統一起見,讓它也返回集合,這樣可以避免同時支持集合與單結果的分支處理,讓代碼更加簡潔、不容易出錯。此外,如果查詢對象不存在的話,我們只返回空集合,並不視為一個錯誤。
查詢輸入/輸出節點的方法實現類似這樣:
查找節點的核心邏輯在資料庫本身定義:
以上使用了內部定義的一些輔助查詢方法。用類似的邏輯再定義 income ,它們的實現都很簡單,讀者可以直接參考源碼,此處不再贅述。
在此步驟的最後,我們再實現一個優化。當多次調用查詢方法後,結果可能會返回重復的數據,很多時候這是不必要的。就像關系資料庫通常支持 unique/distinct 一樣,我們也希望 Dagoba 能夠過濾重復的數據。
假設我們要查詢某人所有孩子的祖父,顯然不管有多少孩子,他們的祖父應該是同一個人。因此編寫測試如下:
現在來實現 unique 。我們只要按照主鍵把重復數據去掉即可:
在上個步驟,初始化資料庫指定了雙向關聯,但並未測試它們。因為我們還沒有編寫代碼去支持它們,現在增加一個測試,它應該是失敗的:
運行測試,的確失敗了。我們看看要如何支持它。回想一下,當從邊查找節點時,使用的是以下方法:
這里也有一個潛在的問題:調用 self.edges 意味著遍歷所有邊,當資料庫內容較多時,這是巨大的浪費。為了提高性能,我們可以把與節點相關的邊記錄在節點本身,這樣要查找邊只要看節點本身即可。在初始化時定義出入邊的集合:
在添加邊時,我們要同時把它們對應的關系同時更新到節點,此外還要維護反向關聯。這涉及對字典內容的部分復制,先編寫一個輔助方法:
然後,將添加邊的實現修改如下:
這里的代碼同時添加正向關聯和反向關聯。有的朋友可能會注意到代碼略有重復,是的,但是重復僅出現在該函數內部,本著「三則重構」的原則,暫時不去提取代碼。
實現之後,前面的測試就可以正常通過了。
在這個步驟中,我們來實現延遲查詢( Lazy Query )。
延遲查詢的要求是,當調用查詢方法時並不立即執行,而是推遲到調用特定方法,比如 run 時才執行整個查詢,返回結果。
延遲查詢的實現要比主動查詢復雜一些。為了實現延遲查詢,查詢方法的實現不能直接返回結果,而是記錄要執行的動作以及傳入的參數,到調用 run 時再依次執行前面記錄下來的內容。
如果你去看作者的實現,會發現他是用一個數據結構記錄執行操作和參數,此外還有一部分邏輯用來分派對每種結構要執行的動作。這樣當然是可行的,但數據處理和分派部分的實現會比較復雜,也容易出錯。
本文的實現則選擇了另外一種不同的方法:使用 Python 的內部函數機制,把一連串查詢變換成一組函數,每個函數取上個函數的執行結果作為輸入,最後一個函數的輸出就是整個查詢的結果。由於內部函數同時也是閉包,盡管每個查詢的參數形式各不相同,但是它們都可以被閉包「捕獲」而成為內部變數,所以這些內部函數可以採用統一的形式,無需再針對每種查詢設計額外的數據結構,因而執行過程得到了很大程度的簡化。
首先還是來編寫測試。 LazyQueryTest 和 EagerQueryTest 測試用例幾乎是完全相同的(是的,兩種查詢只在於內部實現機制不同,它們的調用介面幾乎是完全一致的)。
因此我們可以把 EagerQueryTest 的測試原樣不變拷貝到 LazyQueryTest 中。當然拷貝粘貼不是個好注意,對於比較冗長而固定的初始化部分,我們可以把它提取出來作為兩個測試共享的公共函數。讀者可參考代碼中的 step04_lazy_query/tests/test_lazy_query.py 部分。
程序把查詢函數的串列執行稱為管道( pipeline ),用一個變數來記錄它:
然後依次實現各個調用介面。每種介面的實現都是類似的:用內部函數執行真正的查詢邏輯,再把這個函數添加到 pipeline 調用鏈中。比如 node 的實現類似下面:
其他介面的實現也與此類似。最後, run 函數負責執行所有查詢,返回最終結果;
完成上述實現後執行測試,確保我們的實現是正確的。
在前面我們說過,延遲查詢與主動查詢相比,最大的優勢是對於許多查詢可以按需要訪問,不需要每個步驟都返回完整結果,從而提高性能,節約查詢時間。比如說,對於下面的查詢:
以上查詢的意思是從孫輩中找到一個符合條件的節點即可。對該查詢而言,主動查詢會在調用 outcome('son') 時就遍歷所有節點,哪怕最後一步只需要第一個結果。而延遲查詢為了提高效率,應在找到符合條件的結果後立即停止。
目前我們尚未實現 take 方法。老規矩,先添加測試:
主動查詢的 take 實現比較簡單,我們只要從結果中返回前 n 條記錄:
延遲查詢的實現要復雜一些。為了避免不必要的查找,返回結果不應該是完整的列表( list ),而應該是個按需返回的可迭代對象,我們用內置函數 next 來依次返回前 n 個結果:
寫完後運行測試,確保它們是正確的。
從外部介面看,主動查詢和延遲查詢幾乎是完全相同的,所以用單純的數據測試很難確認後者的效率一定比前者高,用訪問時間來測試也並不可靠。為了測試效率,我們引入一個節點訪問次數的概念,如果延遲查詢效率更高的話,那麼它應該比主動查詢訪問節點的次數更少。
為此,編寫如下測試:
我們為 Dagoba 類添加一個成員來記錄總的節點訪問次數,以及兩個輔助方法,分別用於獲取和重置訪問次數:
然後瀏覽代碼,查找修改點。增加計數主要在從邊查找節點的時候,因此修改部分如下:
此外還有 income/outcome 方法,修改都很簡單,這里就不再列出。
實現後再次運行測試。測試通過,表明延遲查詢確實在效率上優於主動查詢。
不像關系資料庫的結構那樣固定,圖的形式可以千變萬化,查詢機制也必須足夠靈活。從原理上講,所有查詢無非是從某個節點出發按照特定方向搜索,因此用 node/income/outcome 這三個方法幾乎可以組合出任意所需的查詢。
但對於復雜查詢,寫出的代碼有時會顯得較為瑣碎和冗長,對於特定領域來說,往往存在更為簡潔的名稱,例如:母親的兄弟可簡稱為舅舅。對於這些場景,如果能夠類似 DSL (領域特定語言)那樣允許用戶根據專業要求自行擴展,從而簡化查詢,方便閱讀,無疑會更為友好。
如果讀者去看原作者的實現,會發現他是用一種特殊語法 addAlias 來定義自己想要的查詢,調用方法時再進行查詢以確定要執行的內容,其介面和內部實現都是相當復雜的。
而我希望有更簡單的方法來實現這一點。所幸 Python 是一種高度動態的語言,允許在運行時向類中增加新的成員,因此做到這一點可能比預想的還要簡單。
為了驗證這一點,編寫測試如下:
無需 Dagoba 的實現做任何改動,測試就可以通過了!其實我們要做的就是動態添加一個自定義的成員函數,按照 Python 對象機制的要求,成員函數的第一個成員應該是名為 self 的參數,但這里已經是在 UnitTest 的內部,為了和測試類本身的 self 相區分,新函數的參數增加了一個下劃線。
此外,函數應返回其所屬的對象,這是為了鏈式調用所要求的。我們看到,動態語言的靈活性使得添加新語法變得非常簡單。
到此,一個初具規模的圖資料庫就形成了。
和原文相比,本文還缺少一些內容,比如如何將資料庫序列化到磁碟。不過相信讀者都看到了,我們的資料庫內部結構基本上是簡單的原生數據結構(列表+字典),因此序列化無論用 pickle 或是 JSON 之類方法都應該是相當簡單的。有興趣的讀者可以自行完成它們。
我們的圖資料庫實現為了提高查詢性能,在節點內部存儲了邊的指針(或者說引用)。這樣做的好處是,無論資料庫有多大,從一個節點到相鄰節點的訪問是常數時間,因此數據訪問的效率非常高。
但一個潛在的問題是,如果資料庫規模非常大,已經無法整個放在內存中,或者出於安全性等原因要實現分布式訪問的話,那麼指針就無法使用了,必須要考慮其他機制來解決這個問題。分布式資料庫無論採用何種數據模型都是一個棘手的問題,在本文中我們沒有涉及。有興趣的讀者也可以考慮 500lines 系列中關於分布式和集群演算法的其他一些文章。
本文的實現和系列中其他資料庫類似,採用 Python 作為實現語言,而原作者使用的是 JavaScript ,這應該和作者的背景有關。我相信對於大多數開發者來說, Python 的對象機制比 JavaScript 基於原型的語法應該是更容易閱讀和理解的。
當然,原作者的版本比本文版本在實現上其實是更為完善的,靈活性也更好。如果想要更為優雅的實現,我們可以考慮使用 Python 元編程,那樣會更接近於作者的實現,但也會讓程序的復雜性大為增加。如果讀者有興趣,不妨對照著去讀讀原作者的版本。
㈥ 如何評估和測試Mysql及oracle資料庫性能
1:伺服器環境
操作系統:Red Hat Enterprise Linux Server release 5.5 (Tikanga)
CPU:Intel(R) Xeon(R) CPU E5607 @ 2.27GHz 8核
內存:16G
Mysql:Ver 14.14 Distrib 5.5.21, for Linux (x86_64)
Oracle:OracleDatabase 11g Enterprise Edition Release
詳細數據測試(操作通過存儲過程完成)
數據插入
50並發Mysql插入性能圖示(橫坐標:當前數據總量,縱坐標:每秒執行次數){平均值:4841.98}
㈦ 軟體開發資料庫如何進行測試
比如:數據冗餘,功能和性能方面存在的問題已經嚴重影響應用軟體的使用。軟體測試人員往往重視對軟體功能和編碼的測試,而忽略對軟體性能,特別是資料庫訪問並發測試。因為,他們固有的思想中認為資料庫設計存在問題對系統性能影響不大,或從根本上忽略了資料庫在軟體開發中的地位,直到出現了問題,才想到對資料庫的測試,但往往也是僅僅通過對編碼的測試工作中捎帶對資料庫進行一定的測試,這遠遠是不夠的。目前,中鐵網上訂票系統在大用戶同時在線訂票中系統頻頻癱瘓,就是最好的佐證。 所以,在應用軟體的測試工作中,應該將資料庫作為一個獨立的部分進行充分的測試,這樣才可以得到應用軟體所需要的性能優化的資料庫。那麼,應該對哪些內容進行測試,如何進行測試呢? 2、資料庫設計的測試 資料庫是應用的基礎,其性能直接影響應用軟體的性能。為了使資料庫具有較好的性能,需要對資料庫中的表進行規范化設計。規范化的範式可分為第一範式、第二範式、第三範式、BCNF範式、第四範式和第五範式。一般來說,邏輯資料庫設計應滿足第三範式的要求,這是因為滿足第三範式的表結構容易維護,且基本滿足實際應用的要求。因此,實際應用中一般都按照第三範式的標准進行規范化。但是,規范化也有缺點:由於將一個表拆分成為多個表,在查詢時需要多表連接,降低了查詢速度。故資料庫設計的測試包括前期需求分析產生資料庫邏輯模型和後期業務系統開發中的測試兩部分(這里指的是後者),我在這里稱為實體測試。 資料庫是由若乾的實體組成的,包括(表,視圖,存儲過程等),資料庫最基本的測試就是實體測試,通過對這些實體的測試,可以發現資料庫實體設計得是否充分,是否有遺漏,每個實體的內容是否全面,擴展性如何。 實體測試,可以用來發現應用軟體在功能上存在的不足,也可以發現數據冗餘的問題。經過測試,測試人員對有異議的問題要及時和資料庫的設計人員進行溝通解決。 3、數據一致性測試 在進行實體測試後,應進一步檢查下面的內容以保障數據的一致性: 3.1 表的主鍵測試根據應用系統的實際需求,對每個表的主鍵進行測試,驗證是否存在記錄不唯一的情況,如果有,則要重新設置主鍵,使表中記錄唯一。 3.2 表之間主外鍵關系的測試資料庫中主外鍵欄位在名稱,數據類型,欄位長度上的一致性測試。 3.3 級聯表,刪除主表數據後,相應從報表數據應同時刪除的問題例如學生表和學生成績表,學生數據已經刪除,成績表中相應學生的成績記錄應同時刪除。 3.4 存儲過程和觸發器的測試存儲過程可以人工執行,但觸發器不能人工處理,所以在對存儲過程和觸發器執行的過程中針對SQL SERVER2005及以上版本可以使用Microsoft SQL Server Profiler性能測試工具進行測試。 Microsoft SQL Server Profiler 是 SQL 跟蹤的圖形用戶界面,用於監視資料庫引擎或 Analysis Services 的實例。測試人員可以捕獲有關每個事件的數據並將其保存到文件或表中供以後分析。例如:可以對生產環境進行監視,了解哪些存儲過程由於執行速度太慢影響了性能。 4、資料庫的容量測試 隨著資料庫系統的使用,數據量在飛速增長,如何在使用前對數據容量的增長情況進行初步估算,為最終用戶提供參考,這在資料庫使用和維護過程中,是非常重要的。可以通過對資料庫設計中基本表的數據大小,和每天數據表的數據產生量進行初步估算。 記錄數據量=各個欄位所佔位元組數的總和表的數據量=記錄數據量*記錄數資料庫大小=各表數據量的總和 當然,資料庫的大小不僅僅只是基本表的大小,還有系統表,視圖,存儲過程等其它實體所佔的容量,但最基本的數據是表的數據。另外,資料庫的容量還包括資料庫日誌文件的容量,一般應預留資料庫文件的2倍左右。 5、資料庫的性能測試 應用軟體除了功能外,很重要的一部分就是軟體的性能,而對於資料庫系統,資料庫性能的好壞會直接影響應用軟體的性能,這部分的測試,一般手工測試就顯得無能為力了,這時就要藉助自動化的測試軟體,例如:DataFactory,DataFactory是一種強大的數據產生器,它允許開發人員和測試人員很容易產生百萬行有意義的正確的測試資料庫,該工具支持DB2、Oracle、Sybase、SQL Server資料庫。這樣,就可以模擬出應用軟體長期使用後,海量數據存儲的資料庫的性能狀況。從而盡早發現問題,進行資料庫性能的優化。 這里要注意,進行性能測試的時候,一定要注意測試環境的一致性,包括:操作系統、應用軟體的版本以及硬體的配置等,而且在進行資料庫方面的測試的時候一定要注意資料庫的記錄數、配置等要一致,只有在相同條件下進行測試,才可以對結果進行比較。否則無法和用戶對軟體的性能的觀點達成一致。 6、資料庫的壓力測試 說起測試,我們首先想到的就是軟體正確性的測試,即常說的功能測試。軟體功能正確僅是軟體質量合格指標之一。在實際開發中,還有其它的非功能因素也起著決定性的因素,例如軟體的響應速度。影響軟體響應速度的因素有很多,有些是因為演算法不夠高效;還有些可能受用戶並發數的影響。 在眾多類型的軟體測試中,壓力測試正是以軟體響應速度為測試目標,尤其是針對在較短時間內大量並發用戶的訪問時,軟體的抗壓能力。但壓力測試往往是手工難以測試的,必須藉助自動化測試工具。常用的壓力測試有:Web測試、資料庫測試等。 資料庫在大多數軟體項目中是不可缺少的,對於它進行壓力測試是為了找出資料庫對象是否可以有效地承受來自多個用戶的並發訪問。這些對象主要是:索引、觸發器、存儲過程和鎖。通過對SQL語句和存儲過程的測試,自動化的壓力測試工具可以間接的反應資料庫對象是否需要優化。 這些自動化的測試工具很多,各有特點,基於Java的項目可以使用JMeter,.Net項目可以採用.Net集成開發環境中提供的測試方案。 7、結束語 總之,在應用系統的測試中,把資料庫應當作為獨立的系統來測試,這無疑會為應用軟體的質量增加可靠的保障,同時還必須結合應用軟體進行集成測試,只有二者有機結合起來,才能最大限度的發揮資料庫和應用軟體的功能。