本文目录导读:

我来为您提供多种PHP数据库加速方案,从简单到复杂,涵盖不同场景。
基础层优化
PDO 连接池优化
<?php
class DatabasePool {
private static $connections = [];
private static $maxConnections = 10;
public static function getConnection($config) {
$key = md5(json_encode($config));
// 清理过期连接
if (isset(self::$connections[$key])) {
foreach (self::$connections[$key] as $index => $conn) {
if ($conn['expire'] < time()) {
unset(self::$connections[$key][$index]);
}
}
}
// 获取可用连接
if (!empty(self::$connections[$key])) {
foreach (self::$connections[$key] as &$conn) {
if ($conn['in_use'] === false) {
$conn['in_use'] = true;
return $conn['pdo'];
}
}
}
// 创建新连接
$pdo = new PDO(
"mysql:host={$config['host']};dbname={$config['dbname']};charset=utf8mb4",
$config['username'],
$config['password'],
[
PDO::ATTR_PERSISTENT => true,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_STRINGIFY_FETCHES => false
]
);
self::$connections[$key][] = [
'pdo' => $pdo,
'in_use' => true,
'expire' => time() + 3600
];
return $pdo;
}
public static function releaseConnection($pdo) {
foreach (self::$connections as &$connections) {
foreach ($connections as &$conn) {
if ($conn['pdo'] === $pdo) {
$conn['in_use'] = false;
return true;
}
}
}
return false;
}
}
缓存层优化
Redis 缓存助手
<?php
class CacheManager {
private static $redis = null;
private static $cacheEnabled = true;
public static function init() {
if (self::$redis === null && class_exists('Redis')) {
self::$redis = new Redis();
self::$redis->connect('127.0.0.1', 6379);
self::$redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP);
}
}
public static function get($key, $callback, $ttl = 300) {
if (!self::$cacheEnabled || !self::$redis) {
return $callback();
}
$data = self::$redis->get($key);
if ($data === false) {
$data = $callback();
self::$redis->setex($key, $ttl, $data);
}
return $data;
}
public static function delete($key) {
if (self::$redis) {
self::$redis->del($key);
}
}
}
// 使用示例
$users = CacheManager::get('users:top10', function() use ($pdo) {
$stmt = $pdo->query("SELECT * FROM users ORDER BY score DESC LIMIT 10");
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}, 600);
查询优化
查询构建器优化
<?php
class QueryOptimizer {
private $pdo;
private $queryLog = [];
public function __construct($pdo) {
$this->pdo = $pdo;
$this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$this->pdo->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);
}
// 带索引提示的查询
public function queryWithHint($sql, $params = [], $index = null) {
if ($index && strpos($sql, 'USE INDEX') === false) {
preg_match('/FROM\s+(\w+)/i', $sql, $matches);
if (isset($matches[1])) {
$sql = str_replace(
"FROM {$matches[1]}",
"FROM {$matches[1]} USE INDEX ($index)",
$sql
);
}
}
$start = microtime(true);
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
$this->queryLog[] = [
'sql' => $sql,
'time' => microtime(true) - $start,
'rows' => count($result)
];
return $result;
}
// 分页优化
public function paginate($table, $page = 1, $perPage = 20, $conditions = [], $orderBy = 'id DESC') {
$offset = ($page - 1) * $perPage;
// 优化大偏移量查询
if ($offset > 10000) {
$sql = "SELECT * FROM $table WHERE id >
(SELECT id FROM $table ORDER BY id LIMIT $offset, 1)
ORDER BY id LIMIT $perPage";
} else {
$sql = "SELECT * FROM $table ORDER BY $orderBy LIMIT $offset, $perPage";
}
return $this->pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);
}
// 批量插入优化
public function bulkInsert($table, $data, $batchSize = 500) {
$totalChunks = array_chunk($data, $batchSize);
$affectedRows = 0;
foreach ($totalChunks as $chunk) {
$columns = array_keys($chunk[0]);
$placeholders = [];
$values = [];
foreach ($chunk as $row) {
$rowPlaceholders = [];
foreach ($columns as $column) {
$rowPlaceholders[] = '?';
$values[] = $row[$column];
}
$placeholders[] = '(' . implode(',', $rowPlaceholders) . ')';
}
$sql = "INSERT INTO $table (" . implode(',', $columns) . ") VALUES " .
implode(',', $placeholders);
$stmt = $this->pdo->prepare($sql);
$stmt->execute($values);
$affectedRows += $stmt->rowCount();
}
return $affectedRows;
}
// 常用查询结果缓存
public function cachedQuery($key, $sql, $params = [], $ttl = 300) {
return CacheManager::get("query:$key", function() use ($sql, $params) {
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}, $ttl);
}
}
连接复用与预编译
预处理语句池
<?php
class StatementPool {
private static $statements = [];
public static function getStatement($pdo, $sql) {
$hash = md5($sql);
if (isset(self::$statements[$hash])) {
return self::$statements[$hash];
}
$stmt = $pdo->prepare($sql);
self::$statements[$hash] = $stmt;
return $stmt;
}
public static function clear() {
self::$statements = [];
}
}
// 使用示例
$sql = "SELECT * FROM users WHERE age > ? AND status = ?";
$stmt = StatementPool::getStatement($pdo, $sql);
$stmt->execute([25, 'active']);
$users = $stmt->fetchAll();
读写分离
主从数据库配置
<?php
class DatabaseRouter {
private $master;
private $slaves = [];
private static $instance = null;
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function setup($masterConfig, $slaveConfigs) {
$this->master = $this->createConnection($masterConfig);
foreach ($slaveConfigs as $slaveConfig) {
$this->slaves[] = $this->createConnection($slaveConfig);
}
}
private function createConnection($config) {
$pdo = new PDO(
"mysql:host={$config['host']};dbname={$config['dbname']};charset=utf8mb4",
$config['username'],
$config['password'],
[
PDO::ATTR_TIMEOUT => 3,
PDO::ATTR_PERSISTENT => true
]
);
return $pdo;
}
public function getReadConnection() {
if (empty($this->slaves)) {
return $this->master;
}
// 简单的负载均衡
$index = array_rand($this->slaves);
return $this->slaves[$index];
}
public function getWriteConnection() {
return $this->master;
}
public function query($sql, $params = [], $isWrite = false) {
$connection = $isWrite ? $this->getWriteConnection() : $this->getReadConnection();
$stmt = $connection->prepare($sql);
$stmt->execute($params);
return $stmt;
}
}
测试基准脚本
<?php
// benchmark.php
class DatabaseBenchmark {
private $startTime;
private $queries = [];
public function start() {
$this->startTime = microtime(true);
}
public function addQuery($sql, $time) {
$this->queries[] = [
'sql' => $sql,
'time' => $time
];
}
public function getReport() {
$totalTime = microtime(true) - $this->startTime;
$avgTime = $totalTime / count($this->queries);
return [
'total_time' => $totalTime,
'average_time' => $avgTime,
'total_queries' => count($this->queries),
'fastest' => min(array_column($this->queries, 'time')),
'slowest' => max(array_column($this->queries, 'time'))
];
}
}
// 测试示例
$benchmark = new DatabaseBenchmark();
$benchmark->start();
// 测试普通查询 vs 优化查询
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
// 普通查询
$start = microtime(true);
for ($i = 0; $i < 1000; $i++) {
$stmt = $pdo->query("SELECT * FROM users WHERE id = " . rand(1, 10000));
$stmt->fetch();
}
$benchmark->addQuery("直接查询", microtime(true) - $start);
// 预处理查询
$start = microtime(true);
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
for ($i = 0; $i < 1000; $i++) {
$stmt->execute([rand(1, 10000)]);
$stmt->fetch();
}
$benchmark->addQuery("预处理查询", microtime(true) - $start);
// 带缓存查询
$start = microtime(true);
for ($i = 0; $i < 1000; $i++) {
$id = rand(1, 10000);
$result = CacheManager::get("user:$id", function() use ($pdo, $id) {
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$id]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}, 600);
}
$benchmark->addQuery("缓存查询", microtime(true) - $start);
print_r($benchmark->getReport());
监控与日志
<?php
class QueryMonitor {
private static $slowQueries = [];
public static function logQuery($sql, $time, $params = []) {
if ($time > 1.0) { // 慢查询阈值 1秒
self::$slowQueries[] = [
'sql' => $sql,
'time' => $time,
'params' => $params,
'timestamp' => date('Y-m-d H:i:s'),
'backtrace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)
];
if (count(self::$slowQueries) > 100) {
self::saveReport();
}
}
}
private static function saveReport() {
$filename = __DIR__ . '/slow_queries_' . date('Y-m-d') . '.log';
file_put_contents($filename, json_encode(self::$slowQueries, JSON_PRETTY_PRINT), FILE_APPEND);
self::$slowQueries = [];
}
}
最佳实践建议
-
索引优化
- 为常用查询字段加索引
- 使用复合索引
-
查询优化
- 避免SELECT *
- 使用LIMIT限制结果集
- 避免在WHERE中使用函数
-
缓存策略
- 热点数据缓存到Redis
- 使用缓存穿透保护
- 设置合理的过期时间
-
连接管理
- 使用持久连接
- 合理配置连接池大小
-
监控告警
- 记录慢查询
- 监控数据库负载
- 实施自动优化
这些方案可以根据您的具体需求组合使用,从简单到复杂逐步实施,建议先用基准测试脚本评估当前性能,找出瓶颈后再针对性优化。