本文目录导读:

我来为您提供一个完整的ThinkPHP项目关联查询性能测试方案。
测试准备
创建测试数据表
-- 用户表 CREATE TABLE `users` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL, `email` varchar(100) NOT NULL, `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_name` (`name`) ) ENGINE=InnoDB; -- 订单表 CREATE TABLE `orders` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) NOT NULL, `order_no` varchar(50) NOT NULL, `amount` decimal(10,2) NOT NULL, `status` tinyint(1) NOT NULL DEFAULT '1', `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_user_id` (`user_id`), KEY `idx_order_no` (`order_no`) ) ENGINE=InnoDB; -- 订单详情表 CREATE TABLE `order_items` ( `id` int(11) NOT NULL AUTO_INCREMENT, `order_id` int(11) NOT NULL, `product_name` varchar(100) NOT NULL, `price` decimal(10,2) NOT NULL, `quantity` int(11) NOT NULL, PRIMARY KEY (`id`), KEY `idx_order_id` (`order_id`) ) ENGINE=InnoDB;
生成测试数据
<?php
namespace app\common\command;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\facade\Db;
class GenerateTestData extends Command
{
protected function configure()
{
$this->setName('generate:test-data')
->setDescription('生成测试数据');
}
protected function execute(Input $input, Output $output)
{
// 生成10000条用户数据
$users = [];
for ($i = 0; $i < 10000; $i++) {
$users[] = [
'name' => 'user_' . $i,
'email' => 'user' . $i . '@example.com'
];
// 每1000条插入一次
if (count($users) >= 1000) {
Db::name('users')->insertAll($users);
$users = [];
}
}
// 生成50000条订单数据
$orders = [];
for ($i = 0; $i < 50000; $i++) {
$orders[] = [
'user_id' => rand(1, 10000),
'order_no' => 'ORDER' . str_pad($i, 8, '0', STR_PAD_LEFT),
'amount' => rand(100, 10000) / 10,
'status' => rand(1, 5),
'created_at' => date('Y-m-d H:i:s', strtotime('-1 month') + $i * 10)
];
if (count($orders) >= 1000) {
Db::name('orders')->insertAll($orders);
$orders = [];
}
}
// 生成订单详情数据
$items = [];
for ($i = 1; $i <= 50000; $i++) {
$itemCount = rand(1, 5);
for ($j = 0; $j < $itemCount; $j++) {
$items[] = [
'order_id' => $i,
'product_name' => 'product_' . rand(1, 100),
'price' => rand(10, 500) / 10,
'quantity' => rand(1, 10)
];
}
if (count($items) >= 1000) {
Db::name('order_items')->insertAll($items);
$items = [];
}
}
$output->writeln('测试数据生成完成');
}
}
性能测试脚本
基础关联查询测试
<?php
namespace app\api\controller;
use think\facade\Db;
use think\response\Json;
class PerformanceTest extends Base
{
/**
* 测试1:一对多关联查询(hasMany)
*/
public function testHasMany()
{
$startTime = microtime(true);
$startMemory = memory_get_usage();
// 方法1:使用关联查询
$users = Db::name('users')
->alias('u')
->leftJoin('orders o', 'o.user_id = u.id')
->field('u.id, u.name, COUNT(o.id) as order_count')
->group('u.id')
->limit(100)
->select();
$endTime = microtime(true);
$endMemory = memory_get_usage();
return json([
'code' => 1,
'data' => [
'method' => 'JOIN查询',
'time' => round(($endTime - $startTime) * 1000, 2) . 'ms',
'memory' => round(($endMemory - $startMemory) / 1024, 2) . 'KB',
'count' => count($users)
]
]);
}
/**
* 测试2:使用ThinkPHP关联模型
*/
public function testRelationModel()
{
$startTime = microtime(true);
$startMemory = memory_get_usage();
// 使用模型关联
$users = \app\model\User::with(['orders'])
->limit(100)
->select();
$endTime = microtime(true);
$endMemory = memory_get_usage();
return json([
'code' => 1,
'data' => [
'method' => '模型关联',
'time' => round(($endTime - $startTime) * 1000, 2) . 'ms',
'memory' => round(($endMemory - $startMemory) / 1024, 2) . 'KB',
'count' => count($users)
]
]);
}
/**
* 测试3:多级关联查询
*/
public function testMultiLevelRelation()
{
$startTime = microtime(true);
$startMemory = memory_get_usage();
// 查询用户及其订单和订单详情
$users = \app\model\User::with(['orders.items'])
->limit(50)
->select();
$endTime = microtime(true);
$endMemory = memory_get_usage();
return json([
'code' => 1,
'data' => [
'method' => '多级关联',
'time' => round(($endTime - $startTime) * 1000, 2) . 'ms',
'memory' => round(($endMemory - $startMemory) / 1024, 2) . 'KB',
'count' => count($users)
]
]);
}
/**
* 测试4:大数据量分页关联查询
*/
public function testLargeDataPagination()
{
$page = input('page', 1);
$limit = 20;
$startTime = microtime(true);
// JOIN查询带条件
$orders = Db::name('orders')
->alias('o')
->join('users u', 'o.user_id = u.id')
->join('order_items oi', 'oi.order_id = o.id')
->where('o.status', 1)
->field('o.id, o.order_no, o.amount, u.name, COUNT(oi.id) as item_count')
->group('o.id')
->page($page, $limit)
->select();
$endTime = microtime(true);
return json([
'code' => 1,
'data' => [
'method' => '分页JOIN',
'time' => round(($endTime - $startTime) * 1000, 2) . 'ms',
'page' => $page,
'count' => count($orders)
]
]);
}
}
对比测试脚本
<?php
namespace app\common\library;
use think\facade\Db;
use think\facade\Log;
class QueryPerformanceTest
{
// 测试方法集合
protected $tests = [];
public function __construct()
{
$this->tests = [
'simple_query' => '简单查询',
'join_query' => 'JOIN查询',
'relation_query' => '关联模型',
'sub_query' => '子查询',
'batch_query' => '批量查询'
];
}
/**
* 执行所有测试
*/
public function runAllTests($iterations = 100)
{
$results = [];
foreach ($this->tests as $method => $name) {
$results[$name] = $this->benchmark($method, $iterations);
}
return $results;
}
/**
* 基准测试
*/
protected function benchmark($method, $iterations)
{
$times = [];
$memories = [];
for ($i = 0; $i < $iterations; $i++) {
$startTime = microtime(true);
$startMem = memory_get_usage();
// 执行测试方法
call_user_func([$this, $method]);
$endTime = microtime(true);
$endMem = memory_get_usage();
$times[] = ($endTime - $startTime) * 1000;
$memories[] = ($endMem - $startMem) / 1024;
}
return [
'avg_time' => round(array_sum($times) / count($times), 2),
'max_time' => round(max($times), 2),
'min_time' => round(min($times), 2),
'avg_memory' => round(array_sum($memories) / count($memories), 2) . 'KB',
'total_time' => round(array_sum($times), 2)
];
}
/**
* 简单查询
*/
protected function simple_query()
{
return Db::name('users')->limit(100)->select();
}
/**
* JOIN查询
*/
protected function join_query()
{
return Db::name('users')
->alias('u')
->join('orders o', 'o.user_id = u.id')
->field('u.*, COUNT(o.id) as order_count')
->group('u.id')
->limit(100)
->select();
}
/**
* 关联模型查询
*/
protected function relation_query()
{
return \app\model\User::with(['orders'])
->limit(100)
->select();
}
/**
* 子查询
*/
protected function sub_query()
{
$subQuery = Db::name('orders')
->field('user_id, COUNT(*) as order_count')
->group('user_id');
return Db::name('users')
->alias('u')
->join(['' . $subQuery->buildSql() => 'o'], 'o.user_id = u.id')
->limit(100)
->select();
}
/**
* 批量查询
*/
protected function batch_query()
{
$userIds = Db::name('users')->limit(100)->column('id');
$orders = Db::name('orders')
->where('user_id', 'in', $userIds)
->select();
return $orders;
}
}
性能监控工具类
<?php
namespace app\common\library;
use think\facade\Db;
use think\facade\Log;
class QueryMonitor
{
protected $queries = [];
protected $startTime;
protected $startMemory;
/**
* 开始监控
*/
public function start()
{
$this->startTime = microtime(true);
$this->startMemory = memory_get_usage();
// 开启SQL日志
Db::listen(function ($sql, $time, $explain) {
$this->queries[] = [
'sql' => $sql,
'time' => $time,
'explain' => $explain
];
});
}
/**
* 结束监控并返回结果
*/
public function stop()
{
$endTime = microtime(true);
$endMemory = memory_get_usage();
$result = [
'total_time' => round(($endTime - $this->startTime) * 1000, 2) . 'ms',
'memory_usage' => round(($endMemory - $this->startMemory) / 1024, 2) . 'KB',
'query_count' => count($this->queries),
'queries' => $this->queries
];
$this->queries = [];
return $result;
}
/**
* 分析慢查询
*/
public function analyzeSlowQueries($threshold = 100)
{
$slowQueries = array_filter($this->queries, function ($query) use ($threshold) {
return $query['time'] > $threshold;
});
if (!empty($slowQueries)) {
Log::warning('慢查询检测', [
'count' => count($slowQueries),
'queries' => $slowQueries
]);
}
return $slowQueries;
}
}
性能优化实践
查询优化策略
<?php
namespace app\common\library;
class QueryOptimization
{
/**
* 使用索引优化
*/
public function indexOptimization()
{
// 确保索引使用
Db::name('orders')
->where('user_id', 100)
->where('status', 1)
->field('id, order_no, amount')
->select();
// 复合索引
// ALTER TABLE orders ADD INDEX idx_user_status (user_id, status);
}
/**
* 分页优化 - 延迟关联
*/
public function paginationOptimization($page = 1, $limit = 20)
{
// 先查询ID,再关联数据
$ids = Db::name('orders')
->where('status', 1)
->order('id', 'desc')
->limit(($page - 1) * $limit, $limit)
->column('id');
if (empty($ids)) {
return [];
}
$data = Db::name('orders')
->alias('o')
->join('users u', 'o.user_id = u.id')
->where('o.id', 'in', $ids)
->field('o.*, u.name')
->select();
return $data;
}
/**
* 缓存优化
*/
public function cacheOptimization($userId)
{
$cacheKey = 'user_orders_' . $userId;
// 尝试获取缓存
$orders = cache($cacheKey);
if (empty($orders)) {
// 从数据库查询
$orders = Db::name('orders')
->where('user_id', $userId)
->select();
// 存入缓存,有效期5分钟
cache($cacheKey, $orders, 300);
}
return $orders;
}
}
测试执行和报告
<?php
namespace app\api\controller;
use app\common\library\QueryPerformanceTest;
use app\common\library\QueryMonitor;
class TestController
{
/**
* 运行性能测试
*/
public function runTest()
{
// 创建测试实例
$tester = new QueryPerformanceTest();
// 运行所有测试
$results = $tester->runAllTests(50);
// 格式化为报告
$report = $this->formatReport($results);
return json([
'code' => 1,
'data' => $report
]);
}
/**
* 格式化报告
*/
protected function formatReport($results)
{
$html = '<table border="1">';
$html .= '<tr><th>查询方法</th><th>平均耗时</th><th>最大耗时</th><th>最小耗时</th><th>内存使用</th></tr>';
foreach ($results as $name => $data) {
$html .= "<tr>";
$html .= "<td>{$name}</td>";
$html .= "<td>{$data['avg_time']}ms</td>";
$html .= "<td>{$data['max_time']}ms</td>";
$html .= "<td>{$data['min_time']}ms</td>";
$html .= "<td>{$data['avg_memory']}</td>";
$html .= "</tr>";
}
$html .= '</table>';
return $html;
}
}
测试建议
测试场景覆盖
- 不同的数据量级(1万、10万、100万条数据)
- 不同的关联深度(1级、2级、3级关联)
- 不同条件的查询(带where、排序、分组)
- 并发查询测试
监控指标
- 响应时间
- 内存使用
- SQL执行次数
- 索引使用情况
优化建议
根据需要选择不同的查询方式:
- 简单查询:使用
Db类 - 关联查询:使用JOIN或者模型关联
- 大数据量:使用分页和延迟关联
- 频繁查询:使用缓存
注意事项
- 避免N+1查询问题
- 合理使用预加载(
with) - 建立合适的索引
- 避免在大数据量下使用
select * - 使用
findInSet或JSON_CONTAINS时注意性能
这个测试方案可以帮助您全面评估ThinkPHP项目的关联查询性能,并指导您进行相应优化。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播