You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

303 lines
9.7 KiB

#!/usr/bin/env node
/**
* 数据库性能基准测试脚本
* 用于评估数据库优化效果
*/
import db from '../src/db/index.js'
import { UserModel } from '../src/db/models/UserModel.js'
import { ArticleModel } from '../src/db/models/ArticleModel.js'
import { BookmarkModel } from '../src/db/models/BookmarkModel.js'
import { bulkCreate } from '../src/db/transaction.js'
import { getQueryStats, resetStats, getSlowQueries } from '../src/db/monitor.js'
import { DbQueryCache } from '../src/db/index.js'
// 测试配置
const TEST_CONFIG = {
userCount: 1000,
articleCount: 500,
bookmarkCount: 2000,
iterations: 5,
cacheEnabled: true
}
async function setupTestData() {
console.log('准备测试数据...')
// 清空现有数据
await db('bookmarks').del()
await db('articles').del()
await db('users').del()
// 创建测试用户
const usersData = []
for (let i = 1; i <= TEST_CONFIG.userCount; i++) {
usersData.push({
username: `user_${i}`,
email: `user${i}@example.com`,
password: `password_${i}`,
name: `User ${i}`,
role: i % 10 === 0 ? 'admin' : 'user'
})
}
console.log(`创建 ${usersData.length} 个测试用户...`)
await bulkCreate('users', usersData, { batchSize: 100 })
// 创建测试文章
const articlesData = []
for (let i = 1; i <= TEST_CONFIG.articleCount; i++) {
articlesData.push({
title: `Article ${i}`,
content: `This is the content of article ${i}. It contains some sample text for testing purposes.`,
author: `user_${(i % TEST_CONFIG.userCount) + 1}`,
category: `category_${i % 10}`,
status: i % 5 === 0 ? 'draft' : 'published',
view_count: Math.floor(Math.random() * 1000)
})
}
console.log(`创建 ${articlesData.length} 篇测试文章...`)
await bulkCreate('articles', articlesData, { batchSize: 100 })
// 创建测试书签
const bookmarksData = []
for (let i = 1; i <= TEST_CONFIG.bookmarkCount; i++) {
bookmarksData.push({
user_id: (i % TEST_CONFIG.userCount) + 1,
title: `Bookmark ${i}`,
url: `https://example.com/bookmark/${i}`,
description: `Description for bookmark ${i}`
})
}
console.log(`创建 ${bookmarksData.length} 个测试书签...`)
await bulkCreate('bookmarks', bookmarksData, { batchSize: 100 })
console.log('测试数据准备完成!\n')
}
async function runPerformanceTests() {
console.log('开始性能基准测试...\n')
// 重置统计
resetStats()
DbQueryCache.clear()
const results = {
singleQueries: [],
batchQueries: [],
cacheTests: [],
transactionTests: []
}
// 运行多次测试取平均值
for (let i = 0; i < TEST_CONFIG.iterations; i++) {
console.log(`运行第 ${i + 1} 轮测试...`)
// 1. 单记录查询测试
const singleQueryTime = await testSingleRecordQueries()
results.singleQueries.push(singleQueryTime)
// 2. 批量查询测试
const batchQueryTime = await testBatchQueries()
results.batchQueries.push(batchQueryTime)
// 3. 缓存测试
const cacheTestTime = await testCachePerformance()
results.cacheTests.push(cacheTestTime)
// 4. 事务测试
const transactionTime = await testTransactionPerformance()
results.transactionTests.push(transactionTime)
console.log(`${i + 1} 轮测试完成\n`)
}
// 计算平均值并显示结果
displayResults(results)
}
async function testSingleRecordQueries() {
const startTime = Date.now()
// 测试单用户查询
for (let i = 1; i <= 100; i++) {
const userId = (i % TEST_CONFIG.userCount) + 1
await UserModel.findById(userId)
}
// 测试单文章查询
for (let i = 1; i <= 100; i++) {
const articleId = (i % TEST_CONFIG.articleCount) + 1
await ArticleModel.findById(articleId)
}
// 测试单书签查询
for (let i = 1; i <= 100; i++) {
const bookmarkId = (i % TEST_CONFIG.bookmarkCount) + 1
await BookmarkModel.findById(bookmarkId)
}
return Date.now() - startTime
}
async function testBatchQueries() {
const startTime = Date.now()
// 测试用户列表查询
await UserModel.findAll({ page: 1, limit: 50 })
await UserModel.findAll({ page: 2, limit: 50 })
await UserModel.findAll({ page: 3, limit: 50 })
// 测试文章列表查询
await ArticleModel.findAll({ page: 1, limit: 50 })
await ArticleModel.findPublished(0, 50)
await ArticleModel.findDrafts()
// 测试书签列表查询
await BookmarkModel.findAllByUser(1)
await BookmarkModel.findAllByUser(2)
await BookmarkModel.findAllByUser(3)
return Date.now() - startTime
}
async function testCachePerformance() {
const startTime = Date.now()
if (TEST_CONFIG.cacheEnabled) {
// 第一次查询(无缓存)
for (let i = 1; i <= 50; i++) {
await db('users').where('id', i).cache(10000) // 10秒缓存
}
// 第二次查询(有缓存)
for (let i = 1; i <= 50; i++) {
await db('users').where('id', i).cache(10000) // 10秒缓存
}
}
return Date.now() - startTime
}
async function testTransactionPerformance() {
const startTime = Date.now()
// 测试批量创建性能
const testData = []
for (let i = 0; i < 50; i++) {
testData.push({
username: `tx_user_${Date.now()}_${i}`,
email: `tx_user_${Date.now()}_${i}@example.com`,
password: 'password123'
})
}
await bulkCreate('users', testData, { batchSize: 25 })
return Date.now() - startTime
}
function displayResults(results) {
console.log('==================== 性能测试结果 ====================')
console.log(`测试配置: ${TEST_CONFIG.userCount} 用户, ${TEST_CONFIG.articleCount} 文章, ${TEST_CONFIG.bookmarkCount} 书签`)
console.log(`测试轮数: ${TEST_CONFIG.iterations}\n`)
// 计算平均值
const avgSingleQuery = results.singleQueries.reduce((a, b) => a + b, 0) / results.singleQueries.length
const avgBatchQuery = results.batchQueries.reduce((a, b) => a + b, 0) / results.batchQueries.length
const avgCache = results.cacheTests.reduce((a, b) => a + b, 0) / results.cacheTests.length
const avgTransaction = results.transactionTests.reduce((a, b) => a + b, 0) / results.transactionTests.length
console.log('性能指标:')
console.log(`- 单记录查询平均时间: ${avgSingleQuery.toFixed(2)}ms`)
console.log(`- 批量查询平均时间: ${avgBatchQuery.toFixed(2)}ms`)
console.log(`- 缓存查询平均时间: ${avgCache.toFixed(2)}ms`)
console.log(`- 事务处理平均时间: ${avgTransaction.toFixed(2)}ms\n`)
// 显示查询统计
const queryStats = getQueryStats()
console.log('查询统计:')
console.log(`- 总查询数: ${queryStats.totalQueries}`)
console.log(`- 慢查询数: ${queryStats.slowQueries}`)
console.log(`- 慢查询率: ${queryStats.slowQueryRate}%`)
console.log(`- 错误数: ${queryStats.errors}`)
console.log(`- 错误率: ${queryStats.errorRate}%\n`)
// 显示缓存统计
const cacheStats = DbQueryCache.stats()
console.log('缓存统计:')
console.log(`- 缓存项总数: ${cacheStats.size}`)
console.log(`- 有效缓存项: ${cacheStats.valid}`)
console.log(`- 过期缓存项: ${cacheStats.expired}`)
console.log(`- 缓存命中率: ${cacheStats.hitRate ? (cacheStats.hitRate * 100).toFixed(2) : 'N/A'}%`)
console.log(`- 内存使用: ${cacheStats.totalSize ? (cacheStats.totalSize / 1024).toFixed(2) : 0}KB\n`)
// 显示慢查询
const slowQueries = getSlowQueries(5)
if (slowQueries.length > 0) {
console.log('慢查询 (前5个):')
slowQueries.forEach((query, index) => {
console.log(` ${index + 1}. ${query.duration}ms - ${query.sql.substring(0, 100)}...`)
})
console.log('')
}
// 性能评估
console.log('性能评估:')
if (avgSingleQuery < 50) {
console.log('✓ 单记录查询性能优秀')
} else if (avgSingleQuery < 100) {
console.log('○ 单记录查询性能良好')
} else {
console.log('⚠ 单记录查询性能需要优化')
}
if (avgBatchQuery < 200) {
console.log('✓ 批量查询性能优秀')
} else if (avgBatchQuery < 500) {
console.log('○ 批量查询性能良好')
} else {
console.log('⚠ 批量查询性能需要优化')
}
if (queryStats.slowQueryRate < 1) {
console.log('✓ 慢查询率控制良好')
} else {
console.log('⚠ 慢查询率较高,需要优化')
}
console.log('\n🎉 性能基准测试完成!')
}
async function main() {
try {
console.log('数据库性能基准测试\n')
// 准备测试数据
await setupTestData()
// 运行性能测试
await runPerformanceTests()
// 清理测试数据
console.log('\n清理测试数据...')
await db('bookmarks').del()
await db('articles').del()
await db('users').del()
console.log('测试数据清理完成!')
} catch (error) {
console.error('性能测试失败:', error)
process.exit(1)
}
}
// 如果直接运行此脚本,则执行测试
if (import.meta.url === `file://${process.argv[1]}`) {
main()
}
export default main