Gỡ lỗi cơ sở dữ liệu
Kỹ thuật gỡ lỗi cơ sở dữ liệu
Phần tiêu đề “Kỹ thuật gỡ lỗi cơ sở dữ liệu”Các phương pháp và công cụ để gỡ lỗi các truy vấn SQL và các vấn đề về cơ sở dữ liệu trong các ứng dụng XOOPS.
Sơ đồ chẩn đoán
Phần tiêu đề “Sơ đồ chẩn đoán”flowchart TD A[Database Problem] --> B{Query Runs?} B -->|No| C[Check Syntax] B -->|Yes| D{Correct Results?}
C --> C1[Run in MySQL CLI] C1 --> C2[Check EXPLAIN plan] C2 --> C3[Fix SQL]
D -->|No| E[Check Logic] D -->|Yes| F{Performance OK?}
E --> E1[Log result set] E1 --> E2[Verify data] E2 --> E3[Fix query]
F -->|Slow| G[Optimize] F -->|Fast| H[Debugging Complete]
G --> G1[Add indexes] G1 --> G2[Refactor query] G2 --> G3[Retest]Kích hoạt tính năng ghi nhật ký truy vấn
Phần tiêu đề “Kích hoạt tính năng ghi nhật ký truy vấn”Cách 1: Chế độ gỡ lỗi XOOPS
Phần tiêu đề “Cách 1: Chế độ gỡ lỗi XOOPS”<?php// In mainfile.phpdefine('XOOPS_DEBUG_LEVEL', 2);
// Now all queries appear in xoops_log table// Or in files: xoops_data/logs/?>Kiểm tra kết quả:
# View logstail -100 xoops_data/logs/*.log
# Or query databaseSELECT * FROM xoops_log ORDER BY created DESC LIMIT 20;Cách 2: Nhật ký truy vấn chậm MySQL
Phần tiêu đề “Cách 2: Nhật ký truy vấn chậm MySQL”Kích hoạt trong /etc/mysql/my.cnf:
[mysqld]# Enable slow query loggingslow_query_log = 1slow_query_log_file = /var/log/mysql/slow.loglong_query_time = 1 # Log queries > 1 secondlog_queries_not_using_indexes = 1Khởi động lại MySQL:
sudo systemctl restart mysql# orsudo systemctl restart mariadbXem nhật ký:
tail -100 /var/log/mysql/slow.log
# Or analyze with mysqldumpslowmysqldumpslow -s t -t 10 /var/log/mysql/slow.logCách 3: Nhật ký truy vấn chung
Phần tiêu đề “Cách 3: Nhật ký truy vấn chung”Bật cho tất cả truy vấn (cẩn thận: tệp nhật ký lớn):
-- EnableSET GLOBAL general_log = 'ON';SET GLOBAL log_output = 'FILE';SET GLOBAL general_log_file = '/var/log/mysql/general.log';
-- DisableSET GLOBAL general_log = 'OFF';
-- ViewSHOW VARIABLES LIKE 'general_log%';Gỡ lỗi SQL trong Code
Phần tiêu đề “Gỡ lỗi SQL trong Code”Thực thi truy vấn nhật ký
Phần tiêu đề “Thực thi truy vấn nhật ký”<?phprequire_once 'mainfile.php';
$ray = ray(); // If using Ray debugger
// Execute query$query = "SELECT u.uid, u.uname, COUNT(a.id) as total_articles FROM xoops_users u LEFT JOIN xoops_articles a ON u.uid = a.author_id GROUP BY u.uid ORDER BY total_articles DESC";
$ray->label('Query')->info($query);
$result = $GLOBALS['xoopsDB']->query($query);
if (!$result) { $ray->error("SQL Error: " . $GLOBALS['xoopsDB']->error); exit;}
// Log results$data = [];while ($row = $result->fetch_assoc()) { $data[] = $row;}
$ray->label('Results')->dump($data);$ray->info("Found " . count($data) . " rows");?>Đo lường hiệu suất truy vấn
Phần tiêu đề “Đo lường hiệu suất truy vấn”<?php$db = $GLOBALS['xoopsDB'];$ray = ray();
// Measure execution time$start = microtime(true);
$query = "SELECT * FROM xoops_articles LIMIT 1000";$result = $db->query($query);
$exec_time = (microtime(true) - $start) * 1000; // milliseconds
$ray->info("Query executed in: {$exec_time}ms");
// Log slow queriesif ($exec_time > 100) { // Alert if > 100ms $ray->warning("Slow query detected: {$exec_time}ms"); $ray->info($query);}?>Xác minh kết quả truy vấn
Phần tiêu đề “Xác minh kết quả truy vấn”<?php$db = $GLOBALS['xoopsDB'];$ray = ray();
$query = "SELECT * FROM xoops_articles WHERE author_id = 5";$result = $db->query($query);
// Check if query succeededif (!$result) { $ray->error("Query failed: " . $db->error); exit;}
// Get row count$count = $result->num_rows;$ray->info("Query returned: $count rows");
// Fetch results$articles = [];while ($row = $result->fetch_assoc()) { $articles[] = $row;}
// Verify dataif (empty($articles)) { $ray->warning("No articles found for author 5");} else { $ray->success("Found " . count($articles) . " articles"); $ray->dump($articles);}?>Phân tích hiệu suất truy vấn
Phần tiêu đề “Phân tích hiệu suất truy vấn”GIẢI THÍCH Lệnh
Phần tiêu đề “GIẢI THÍCH Lệnh”Sử dụng EXPLAIN để phân tích việc thực hiện truy vấn:
-- Analyze a queryEXPLAIN SELECT * FROM xoops_articles WHERE author_id = 5;
-- With extended informationEXPLAIN EXTENDED SELECT * FROM xoops_articles WHERE author_id = 5;
-- JSON format (shows more details)EXPLAIN FORMAT=JSON SELECT * FROM xoops_articles WHERE author_id = 5\GCác trường chính cần kiểm tra:
type: ALL (bad) - Full table scan INDEX (ok) - Index scan ref/const (good) - Direct index lookup range (ok) - Range scan using index
possible_keys: Indexes availablekey: Index actually usedkey_len: Length of index usedrows: Estimated rows examinedExtra: Additional info (Using where, Using index, etc.)Phân tích ví dụ
Phần tiêu đề “Phân tích ví dụ”-- Slow query without indexEXPLAIN SELECT * FROM xoops_articles WHERE author_id = 5;
+----+-------------+----------+------+---------------+------+---------+------+-------+-------------+| id | select_type | table | type | possible_keys | key | key_len | rows | Extra |+----+-------------+----------+------+---------------+------+---------+------+-------+-------------+| 1 | SIMPLE | articles | ALL | NULL | NULL | NULL | 1000 | Using where |+----+-------------+----------+------+---------------+------+-------+------+-------+-------------+ ↑ No index available!
-- After adding indexALTER TABLE xoops_articles ADD INDEX (author_id);
EXPLAIN SELECT * FROM xoops_articles WHERE author_id = 5;
+----+-------------+----------+------+---------------+-----------+---------+-------+------+| id | select_type | table | type | possible_keys | key | key_len | rows | Extra|+----+-------------+----------+------+---------------+-----------+---------+-------+------+| 1 | SIMPLE | articles | ref | author_id | author_id | 4 | 10 |+----+-------------+----------+------+---------------+-----------+---------+-------+------+ ↑ Using index - much faster!Các sự cố thường gặp về SQL
Phần tiêu đề “Các sự cố thường gặp về SQL”1. Vấn đề truy vấn N+1
Phần tiêu đề “1. Vấn đề truy vấn N+1”Vấn đề:
<?php// WRONG: Multiple queries in loop$authors = $db->query("SELECT uid FROM xoops_users LIMIT 100");while ($author = $authors->fetch_assoc()) { // This executes 100 times! $articles = $db->query( "SELECT COUNT(*) FROM xoops_articles WHERE author_id = " . $author['uid'] ); echo $articles->fetch_row()[0];}?>Giải pháp: Sử dụng THAM GIA
<?php// CORRECT: One query$result = $db->query(" SELECT u.uid, u.uname, COUNT(a.id) as total FROM xoops_users u LEFT JOIN xoops_articles a ON u.uid = a.author_id GROUP BY u.uid LIMIT 100");
while ($row = $result->fetch_assoc()) { echo $row['total'];}?>2. Thiếu chỉ mục
Phần tiêu đề “2. Thiếu chỉ mục”Xác định:
-- Find queries that scan all rowsSELECT * FROM xoops_logWHERE info LIKE '%type: ALL%'ORDER BY created DESC;Thêm chỉ mục:
-- Single column indexALTER TABLE xoops_articles ADD INDEX (author_id);ALTER TABLE xoops_articles ADD INDEX (created);
-- Composite indexALTER TABLE xoops_articles ADD INDEX (author_id, created);
-- Unique indexALTER TABLE xoops_articles ADD UNIQUE INDEX (slug);3. Điều kiện WHERE không hiệu quả
Phần tiêu đề “3. Điều kiện WHERE không hiệu quả”Vấn đề:
-- Wrong: Functions prevent index useSELECT * FROM xoops_articlesWHERE YEAR(created) = 2024;
-- Wrong: OR with different columnsSELECT * FROM xoops_articlesWHERE category = 'tech' OR author_id = 5;Giải pháp:
-- Correct: Use rangeSELECT * FROM xoops_articlesWHERE created >= '2024-01-01' AND created < '2025-01-01';
-- Correct: Use UNION for different columnsSELECT * FROM xoops_articles WHERE category = 'tech'UNIONSELECT * FROM xoops_articles WHERE author_id = 5;Gỡ lỗi các vấn đề cụ thể
Phần tiêu đề “Gỡ lỗi các vấn đề cụ thể”Vấn đề: Truy vấn trả về kết quả sai
Phần tiêu đề “Vấn đề: Truy vấn trả về kết quả sai”<?php$ray = ray();
// Test with sample data$author_id = 5;$ray->info("Searching for author_id = $author_id");
$query = "SELECT * FROM xoops_articles WHERE author_id = ?";$stmt = $db->prepare($query);$stmt->bind_param("i", $author_id);$stmt->execute();
$result = $stmt->get_result();$count = $result->num_rows;
$ray->info("Found: $count articles");
// Check if parameterized query helpsif ($count == 0) { // Try without parameter to debug $debug_query = "SELECT * FROM xoops_articles WHERE author_id = $author_id"; $ray->warning("Debug query: $debug_query");}
// Dump first resultif ($row = $result->fetch_assoc()) { $ray->label('First Result')->dump($row);}?>Vấn đề: Truy vấn tham gia chậm
Phần tiêu đề “Vấn đề: Truy vấn tham gia chậm”<?php$ray = ray();
$query = " SELECT a.id, a.title, u.uname, u.email FROM xoops_articles a LEFT JOIN xoops_users u ON a.author_id = u.uid WHERE a.status = 1 ORDER BY a.created DESC LIMIT 50";
$ray->info("Running join query");$ray->measure(function() use ($query) { $result = $GLOBALS['xoopsDB']->query($query); return $result;});
// Analyze with EXPLAIN$ray->label('Query Analysis')->info($query);?>Chạy GIẢI THÍCH:
EXPLAIN SELECT a.id, a.title, u.uname, u.emailFROM xoops_articles aLEFT JOIN xoops_users u ON a.author_id = u.uidWHERE a.status = 1ORDER BY a.created DESCLIMIT 50\G
-- Look for:-- - type: ALL (need index)-- - Extra: Using temporary; Using filesort (inefficient)-- Fix: Add composite indexALTER TABLE xoops_articles ADD INDEX (status, created);Tạo nhật ký truy vấn gỡ lỗi
Phần tiêu đề “Tạo nhật ký truy vấn gỡ lỗi”<?php// Create modules/yourmodule/QueryLogger.php
class QueryLogger { private static $queries = []; private static $times = [];
public static function log($query) { self::$queries[] = $query; self::$times[] = microtime(true); }
public static function execute($query) { $start = microtime(true); $result = $GLOBALS['xoopsDB']->query($query); $time = (microtime(true) - $start) * 1000;
self::log($query); self::$times[count(self::$times) - 1] = $time;
return $result; }
public static function report() { echo "<h1>Query Report</h1>"; echo "<table>"; echo "<tr><th>Query</th><th>Time (ms)</th></tr>";
foreach (self::$queries as $i => $query) { $time = self::$times[$i] ?? 0; echo "<tr>"; echo "<td><pre>" . htmlspecialchars(substr($query, 0, 100)) . "</pre></td>"; echo "<td>" . number_format($time, 2) . "</td>"; echo "</tr>"; }
echo "</table>"; }
public static function getTotalQueries() { return count(self::$queries); }
public static function getTotalTime() { return array_sum(self::$times); }}?>Cách sử dụng:
<?phprequire_once 'QueryLogger.php';
$result = QueryLogger::execute("SELECT * FROM xoops_articles");
// Later...echo "Total queries: " . QueryLogger::getTotalQueries();echo "Total time: " . QueryLogger::getTotalTime() . "ms";QueryLogger::report();?>Danh sách kiểm tra tối ưu hóa cơ sở dữ liệu
Phần tiêu đề “Danh sách kiểm tra tối ưu hóa cơ sở dữ liệu”graph TD A[Database Optimization] --> B["1. Identify Issues"] A --> C["2. Add Indexes"] A --> D["3. Refactor Queries"] A --> E["4. Monitor"]
B --> B1["✓ Enable slow log"] B --> B2["✓ Check EXPLAIN"] B --> B3["✓ Profile code"]
C --> C1["✓ Single column"] C --> C2["✓ Composite"] C --> C3["✓ Unique"]
D --> D1["✓ Remove N+1"] D --> D2["✓ Use JOINs"] D --> D3["✓ Add WHERE"]
E --> E1["✓ Watch slow log"] E --> E2["✓ Monitor size"] E --> E3["✓ Clean old data"]Truy vấn MySQL hữu ích
Phần tiêu đề “Truy vấn MySQL hữu ích”-- Find slow tablesSELECT * FROM xoops_logWHERE info LIKE '%type: ALL%'ORDER BY created DESC LIMIT 20;
-- List all indexesSHOW INDEX FROM xoops_articles;
-- Find duplicate indexesSELECT a.table_name, a.index_name, a.seq_in_index, a.column_nameFROM information_schema.statistics aJOIN information_schema.statistics b ON a.table_name = b.table_name AND a.seq_in_index = b.seq_in_index AND a.column_name = b.column_name AND a.index_name != b.index_nameWHERE a.table_name LIKE 'xoops_%';
-- Table sizesSELECT table_name, ROUND(((data_length + index_length) / 1024 / 1024), 2) AS size_mbFROM information_schema.tablesWHERE table_schema = 'xoops_db'ORDER BY size_mb DESC;
-- Find unused indexesSELECT * FROM performance_schema.table_io_waits_summary_by_index_usageWHERE object_schema != 'mysql'AND count_star = 0ORDER BY object_name;Tài liệu liên quan
Phần tiêu đề “Tài liệu liên quan”- Kích hoạt chế độ gỡ lỗi
- Sử dụng trình gỡ lỗi Ray
- Câu hỏi thường gặp về hiệu suất
- Cơ sở dữ liệu cơ bản
#xoops #database #debugging #sql #optimization #mysql