MySQL Shell 模組提供了一套便捷的工具,用於管理和執行資料函式庫工作負載。其核心功能包含載入測試資料、執行預定義的工作負載以及提供效能監控和分析工具。使用者可以透過 load() 方法載入 employees、sakila 和 world 等測試資料函式庫,並使用 run() 方法執行預先定義的工作負載。此外,模組還內建了多個 Python 函式庫,例如 innodb_buffer_pool、innodb_monitor 和 innodb_mutex,用於監控 InnoDB 引擎的關鍵指標,例如緩衝池狀態、mutex 等待事件等,方便開發者進行效能分析和調校。透過 sys.metrics 檢視,使用者可以收集更全面的效能指標,並利用提供的工具將資料輸出為 CSV 格式,以便進一步分析。
MySQL Shell 模組安裝與使用
MySQL Shell 提供了一個強大的模組系統,允許使用者擴充套件其功能。本文將指導您如何安裝並使用 concurrency_book 模組。
安裝步驟
下載模組檔案:首先,您需要從本文的 GitHub 儲存函式庫下載
concurrency_book目錄下的所有檔案。您可以透過克隆儲存函式庫或下載 ZIP 檔案來完成此操作。- 克隆儲存函式庫:使用 Git 軟體克隆儲存函式庫,網址可透過本文的首頁(www.apress.com/gp/book/9781484266519)找到。
- 下載 ZIP 檔案:直接下載包含所有檔案的 ZIP 檔案。
選擇安裝路徑:您可以自由選擇存放這些檔案的路徑,但需保持
concurrency_book目錄以下的結構不變。本文假設您將檔案存放於C:\Book\mysql-concurrency。組態 MySQL Shell:為了能夠在 MySQL Shell 中匯入模組,您需要編輯或建立
mysqlshrc.py檔案。MySQL Shell 會在四個預設位置搜尋此檔案(Windows 系統):%PROGRAMDATA%\MySQL\mysqlsh\%MYSQLSH_HOME%\shared\mysqlsh\<mysqlsh binary path>\%APPDATA%\MySQL\mysqlsh\
在
mysqlshrc.py檔案中,您需要新增以下程式碼,以將模組所在的目錄加入 Python 的搜尋路徑中:import sys sys.path.append('C:\\Book\\mysql-concurrency') import concurrency_book.generate請根據您的實際路徑調整上述程式碼中的路徑。
使用模組
concurrency_book.generate 模組提供了多個方法來簡化您的操作,主要包括 help()、load()、show() 和 run()。
help() 方法
此方法提供關於如何使用該模組的資訊。
mysql-py> concurrency_book.generate.help()
輸出結果將顯示支援的操作,包括:
help():顯示幫助資訊。load(schema_name=None):載入一個 schema,可選地接受 schema 名稱。show():列出可用的工作負載。run(workload_name=None):執行一個工作負載,可選地接受工作負載名稱。
show() 方法
此方法列出可用的工作負載和可載入的 schema。
mysql-py> concurrency_book.generate.show()
輸出結果將顯示可用的工作負載列表,包括名稱和描述。
程式碼解說
組態 MySQL Shell 的 Python 程式碼
import sys
sys.path.append('C:\\Book\\mysql-concurrency')
import concurrency_book.generate
內容解密:
import sys:匯入 Python 的sys模組,該模組提供了對 Python 直譯器相關變數和函式的存取。sys.path.append('C:\\Book\\mysql-concurrency'):將指定的路徑新增到 Python 的模組搜尋路徑中,使得 MySQL Shell 可以找到concurrency_book模組。import concurrency_book.generate:匯入concurrency_book模組中的generate部分,使其功能可在 MySQL Shell 中使用。
使用 help() 方法
mysql-py> concurrency_book.generate.help()
內容解密:
concurrency_book.generate.help():呼叫generate模組中的help()方法,顯示如何使用該模組的資訊。
使用 show() 方法
mysql-py> concurrency_book.generate.show()
內容解密:
concurrency_book.generate.show():呼叫generate模組中的show()方法,列出可用的工作負載和可載入的 schema。
MySQL Shell 模組使用
MySQL Shell 模組是一個強大的工具,用於載入測試資料和執行工作負載。本將介紹如何使用此模組。
載入測試資料
MySQL Shell 模組支援載入 employees、sakila 和 world 範例資料函式庫到您的 MySQL 例項中。對於 employees 資料函式庫,您可以選擇帶有分割槽的版本。world 資料函式庫是本文最重要的資料函式庫,其次是 sakila 資料函式庫。employees 資料函式庫僅用於第 18 章的案例研究。
載入資料函式庫的步驟:
- 使用
load()方法載入資料函式庫。如果您不提供資料函式庫名稱,則會提示您選擇。 - 選擇要載入的資料函式庫編號或名稱。
- 如果資料函式庫已經存在,它將被刪除並重新載入。
mysql-py> concurrency_book.generate.load()
可用的資料函式庫載入作業:
| 編號 | 名稱 | 描述 |
|---|---|---|
| 1 | employees | 員薪水料函式庫 |
| 2 | employees partitioned | 帶有分割槽的員薪水料函式庫 |
| 3 | sakila | sakila 資料函式庫 |
| 4 | world | world 資料函式庫 |
執行工作負載
使用 run() 方法執行工作負載。如果您指定已知工作負載的名稱,則該工作負載將立即執行。否則,將列出可用的工作負載,並提示您選擇。
執行工作負載的步驟:
- 使用
run()方法執行工作負載。 - 如果需要,選擇要執行的工作負載編號或名稱。
mysql-py> concurrency_book.generate.run()
小貼士
- 如果您的網路連線不穩定,下載 employees 資料函式庫可能會失敗。您可以手動下載 https://github.com/datacharmer/test_db/archive/master.zip 並將其儲存在 sample_data 目錄中。
- 如果載入過程當機並抱怨檔案損壞,請刪除該檔案並重新下載。
內容解密:
本段落詳細介紹了 MySQL Shell 模組的使用方法,包括如何載入測試資料和執行工作負載。透過使用 load() 和 run() 方法,您可以輕鬆地管理和執行各種測試任務。同時,本也提供了一些實用的小貼士,以幫助您避免常見的問題。透過遵循本的指示,您可以更好地利用 MySQL Shell 模組來滿足您的測試需求。
MySQL Shell 模組的實際操作與分析
使用 Prompt 執行工作負載
在 MySQL Shell 中,可以使用 concurrency_book.generate.run() 命令來執行特定的工作負載。此命令會列出可用的工作負載,並允許使用者選擇要執行的專案。
執行工作負載:使用者層級鎖定死鎖範例
在範例中,使用者選擇了編號 15 的工作負載,即「Listing 6-1: A deadlock for user-level locks」。此範例模擬了兩個連線之間的死鎖情況。
程式碼範例
-- Connection 1
SELECT GET_LOCK('my_lock_1', -1);
-- Connection 2
SELECT GET_LOCK('my_lock_2', -1);
-- Connection 2
SELECT GET_LOCK('my_lock_1', -1);
-- Connection 1
SELECT GET_LOCK('my_lock_2', -1);
內容解密:
第一步驟: 連線 1 取得鎖
my_lock_1,連線 2 取得鎖my_lock_2。- 使用
GET_LOCK函式嘗試取得鎖,若成功則傳回 1。
- 使用
第二步驟: 連線 2 嘗試取得鎖
my_lock_1,而連線 1 嘗試取得鎖my_lock_2。- 由於雙方都持有對方需要的鎖,因此會發生死鎖。
錯誤處理: 當發生死鎖時,MySQL 會傳回錯誤程式碼 3058,並提示嘗試回復交易或釋放鎖後重試。
調查與分析
在發生死鎖後,可以使用 performance_schema 中的表格來調查鎖的情況和事件歷史。
可用的調查查詢
- 查詢 metadata_locks 表格
SELECT * FROM performance_schema.metadata_locks WHERE object_type = ‘USER LEVEL LOCK’ AND owner_thread_id IN (249, 250);
2. **查詢 events_statements_history 表格(針對特定 thread_id)**
```sql
SELECT thread_id, event_id, sql_text,
mysql_errno, returned_sqlstate, message_text,
errors, warnings
FROM performance_schema.events_statements_history
WHERE thread_id = 249 AND event_id > 6
ORDER BY event_id;
調查結果分析
透過查詢 events_statements_history,可以檢視特定執行緒的事件歷史。例如,對於 thread_id = 249 的查詢結果顯示了以下事件:
- 事件 7:執行
SELECT GET_LOCK('my_lock_1', -1)成功。 - 事件 8:執行
SELECT GET_LOCK('my_lock_2', -1)發生死鎖錯誤(錯誤程式碼 3058)。 - 事件 9:執行
SHOW WARNINGS。
這些資訊有助於瞭解發生死鎖時的具體情況和錯誤原因。
MySQL Shell 模組內部結構與使用
MySQL Shell 模組是一個強大的工具,用於執行和管理 MySQL 資料函式庫的平行工作負載。本將探討該模組的內部結構、使用方法以及如何擴充套件其功能。
模組結構
該模組的檔案可以分為三類別,如圖 B-2 所示。
generate.py檔案是模組的入口點,實作了四個公開方法:help()、load()、show()和run()。libs目錄包含各種函式庫,用於實作模組的功能。這些函式庫也可以用於實作自定義的工作負載。workloads目錄包含工作負載的定義,每個工作負載都有一個 YAML 檔案,部分測試案例還包含 Python 檔案。
使用
執行工作負載
- 使用
run()方法執行工作負載,該方法會提示輸入 MySQL 帳戶的密碼。 - 執行工作負載前,會顯示連線的 Processlist ID、Thread ID 和 Event ID 等資訊。
- 執行工作負載後,可以執行調查查詢來分析問題。
- 使用
調查查詢
- 調查查詢用於分析工作負載執行的結果。
- 可以透過指定查詢編號來執行調查查詢。
- 調查查詢的結果以註解形式顯示,註明執行的查詢編號。
離開工作負載
- 提交空答案以離開工作負載。
- 如果不想執行更多工作負載,再次提交空答案以離開
run()方法。
函式庫檔案
該模組提供了多個有用的函式庫,用於實作複雜的工作負載。
innodb_buffer_pool.py
- 該模組實作了監控 InnoDB 緩衝池的介面。
- 需要提供一個連線到 MySQL 的 MySQL Shell session 物件。
- 示例用法:
from concurrency_book import libs
import concurrency_book.libs.innodb_buffer_pool
bp_stats = libs.innodb_buffer_pool.Stats(session)
bp_stats.collect()
...
bp_stats.collect()
young = bp_stats.delta('pages_made_young')
print(f'Made young ......: {young.value:6d} pages ' +
f'({young.rate:8.2f} pages/s)')
innodb_monitor.py
- 該模組實作了監控 InnoDB 監控輸出的介面。
- 可以傳回個別區段的內容,並對 SEMAPHORES 區段進行統計。
- 需要提供一個連線到 MySQL 的 MySQL Shell session 物件。
- 示例用法:
from concurrency_book import libs
import concurrency_book.libs.innodb_monitor
innodb = libs.innodb_monitor.InnodbMonitor(session)
innodb.fetch()
semaphores = innodb.get_section('SEMAPHORES')
if semaphores.num_waits >= 2:
print(r'mysql> SHOW ENGINE INNDB STATUS\G')
print('...')
print(semaphores.content)
print('...')
innodb_mutex.py
- 該模組實作了監控 SHOW ENGINE INNODB MUTEX 輸出的介面。
- 可以取得總等待次數和與前一次輸出的差異。
- 需要提供一個連線到 MySQL 的 MySQL Shell session 物件。
- 示例用法:
from concurrency_book import libs
import concurrency_book.libs.innodb_mutex
mutex = libs.innodb_mutex.InnodbMutexMonitor(session)
mutex.fetch()
...
MySQL 並發測試工具的模組解析
MySQL 並發測試工具是由多個 Python 模組組成,這些模組共同協助完成並發測試、資料載入、效能監控及查詢格式化等任務。以下將詳細介紹這些模組的功能及其實作方式。
mutex.py 模組
mutex.py 模組主要用於分析 InnoDB 的 mutex 等待事件。它透過 delta_by_file() 和 delta_by_file_line() 方法,分別按檔案名稱和檔案名稱:行號來統計等待次數。這些方法可以傳回結果為字典或以 MySQL 表格格式呈現的報告。
mutex.fetch()
delta = mutex.delta_by_file('dict')
if delta['btr0sea.cc'] > 0:
print(mutex.delta_by_file_line('report'))
內容解密:
mutex.fetch():取得最新的 mutex 等待事件資料。delta = mutex.delta_by_file('dict'):計算各檔案的等待次數變化,並以字典形式傳回結果。if delta['btr0sea.cc'] > 0::檢查特設定檔案(如btr0sea.cc)的等待次數是否大於 0。print(mutex.delta_by_file_line('report')):若條件滿足,則列印預出按檔案名稱和行號統計的等待次數報告。
load.py 模組
load.py 模組負責載入測試資料。要支援新的 schema,需要在 KNOWN_SCHEMAS 和 URLS 常數中新增相關資訊,並實作 _exec_<schema name>() 方法。例如,對於 world schema,需要定義 _exec_world() 方法。
def _exec_world(self):
"""執行載入 world schema 的步驟"""
file = self._download()
with zipfile.ZipFile(file) as zip_fs:
self._delimiter = ';'
with zip_fs.open('world.sql') as world:
self._sql_file(world, zip_fs)
LOG.info('Load of the world schema completed')
return True
內容解密:
file = self._download():下載包含 SQL 陳述式的壓縮檔案。with zipfile.ZipFile(file) as zip_fs::使用zipfile模組直接存取壓縮檔案中的內容,而無需顯式解壓縮。self._sql_file(world, zip_fs):執行 SQL 檔案中的陳述式以載入 schema。LOG.info('Load of the world schema completed'):記錄載入完成的資訊。
log.py 模組
log.py 模組提供日誌記錄功能,支援在多執行緒環境中安全地列印日誌。可以透過設定鎖定物件來確保執行緒安全。
LOG = libs.log.Log(libs.log.INFO)
lock = threading.Lock()
LOG.lock = lock
LOG.debug('Some debug information.')
LOG.info('Some informational content.')
內容解密:
LOG = libs.log.Log(libs.log.INFO):初始化日誌物件,設定預設日誌級別為 INFO。lock = threading.Lock():建立一個鎖定物件用於同步。LOG.lock = lock:將鎖定物件賦予日誌物件,以確保執行緒安全的日誌記錄。LOG.debug()和LOG.info():分別記錄除錯資訊和一般資訊。
metrics.py 模組
metrics.py 模組允許監控 sys.metrics 檢視,用於收集各種效能指標。它需要一個連線到 MySQL 的 MySQL Shell session 物件。
metrics = libs.metrics.Metrics(session)
for i in range(10):
metrics.collect()
sleep(1)
metrics.collect()
count_metrics = ['innodb_row_lock_current_waits', 'lock_row_lock_current_waits']
delta_metrics = ['innodb_row_lock_time', 'lock_deadlocks', 'lock_timeouts']
metrics.write_csv(count_metrics)
metrics.write_rate_csv(delta_metrics)
內容解密:
metrics = libs.metrics.Metrics(session):初始化 Metrics 物件,需要一個 MySQL Shell session。metrics.collect():收集效能指標。count_metrics和delta_metrics:定義了兩類別效能指標,分別用於統計和計算變化率。write_csv()和write_rate_csv():將收集到的指標以 CSV 格式輸出。
query.py 模組
query.py 模組提供了與執行工作負載和調查查詢相關的工具。其中,Formatter() 類別可用於格式化查詢陳述式,包括新增縮排和替換引數佔位符。
sql_formatter = libs.query.Formatter([6, 7], [12, 14], [6, 6])
sql = """SELECT * FROM world.city""".strip()
print('mysql> ' + sql_formatter.indent_sql(sql, 7))
內容解密:
sql_formatter = libs.query.Formatter([6, 7], [12, 14], [6, 6]):初始化 Formatter 物件,需要提供 process list ids、thread ids 和 last event id。sql_formatter.indent_sql(sql, 7):格式化 SQL 陳述式,新增適當的縮排。