365health-365体育投注网站官网-365bet官网投注

MySQL 连接池管理操作指南

MySQL 连接池管理操作指南

MySQL 连接池管理操作指南本指南专注于解决 MySQL 连接池使用中的常见问题,提供配置优化、问题诊断和性能调优的实用方案。

为什么需要连接池?连接池的价值1. 减少连接开销

建立一个 MySQL 连接需要:

TCP 三次握手(网络往返)MySQL 身份验证(用户名/密码验证)字符集协商初始化会话状态通常需要 50-200ms,而连接池复用连接仅需 1-5ms。

2. 控制资源使用

MySQL 服务器的连接数有限制(默认 151):

SHOW VARIABLES LIKE 'max_connections';

-- +-------------------+-------+

-- | Variable_name | Value |

-- +-------------------+-------+

-- | max_connections | 151 |

-- +-------------------+-------+连接池确保不超过服务器限制。

3. 提升并发能力

-- 无连接池:每次请求都建立新连接(慢)

function handle_request()

local db = mysql.open{...} -- 100ms 连接开销

local result = db:query("SELECT * FROM users") -- 10ms 查询

db:close()

return result

end

-- 有连接池:复用连接(快)

local pool = mysql.open{...} -- 只建立一次

function handle_request()

local result = pool:query("SELECT * FROM users") -- 10ms 查询

return result

end连接池配置基础配置参数local mysql = require "silly.store.mysql"

local pool = mysql.open {

-- 连接信息

addr = "127.0.0.1:3306",

user = "app_user",

password = "app_password",

database = "mydb",

charset = "utf8mb4",

-- 连接池参数

max_open_conns = 20, -- 最大打开连接数(0 = 无限制)

max_idle_conns = 5, -- 最大空闲连接数(0 = 无限制)

max_idle_time = 600, -- 空闲连接超时时间(秒,0 = 不超时)

max_lifetime = 3600, -- 连接最大生命周期(秒,0 = 不限制)

max_packet_size = 1024 * 1024, -- 最大数据包大小(字节)

}参数详解max_open_conns(最大连接数)控制与数据库的最大并发连接数。

-- 设置为 20:同时最多 20 个查询

max_open_conns = 20

-- 第 21 个请求会等待,直到有连接释放如何选择:

max_open_conns = 并发查询数 × 1.2示例:

100 QPS,每个查询 50ms → 并发 = 100 × 0.05 = 5 → 设置 101000 QPS,每个查询 100ms → 并发 = 1000 × 0.1 = 100 → 设置 120max_idle_conns(最大空闲连接)控制连接池中保持的空闲连接数量。

-- 设置为 5:连接池保持 5 个空闲连接

max_idle_conns = 5

-- 超过 5 个的空闲连接会被关闭如何选择:

max_idle_conns = max_open_conns × 0.3建议:

低负载:max_idle_conns = 2-5(节省资源)高负载:max_idle_conns = max_open_conns × 0.5(快速响应)max_idle_time(空闲超时)空闲连接在池中保持的最长时间。

-- 设置为 600 秒(10 分钟)

max_idle_time = 600

-- 空闲超过 10 分钟的连接会被关闭如何选择:

频繁访问:600-1800 秒(10-30 分钟)偶尔访问:60-300 秒(1-5 分钟)需要检测断线:300 秒(MySQL wait_timeout 通常 28800 秒)max_lifetime(连接生命周期)连接的最大存活时间(无论是否空闲)。

-- 设置为 3600 秒(1 小时)

max_lifetime = 3600

-- 连接使用超过 1 小时后会被关闭并重建如何选择:

防止连接泄漏:3600 秒(1 小时)频繁重建:1800 秒(30 分钟)长期稳定:7200 秒(2 小时)注意:应小于 MySQL 的 wait_timeout。

不同负载下的推荐配置低负载应用(内部工具、管理后台)local pool = mysql.open {

addr = "127.0.0.1:3306",

user = "app_user",

password = "app_password",

database = "mydb",

charset = "utf8mb4",

max_open_conns = 5, -- 最多 5 个并发查询

max_idle_conns = 2, -- 保持 2 个空闲连接

max_idle_time = 300, -- 5 分钟空闲超时

max_lifetime = 1800, -- 30 分钟最大生命周期

}适用场景:

并发请求 < 10QPS < 100查询响应时间 < 100ms中等负载应用(小型 Web 服务)local pool = mysql.open {

addr = "127.0.0.1:3306",

user = "app_user",

password = "app_password",

database = "mydb",

charset = "utf8mb4",

max_open_conns = 20, -- 最多 20 个并发查询

max_idle_conns = 5, -- 保持 5 个空闲连接

max_idle_time = 600, -- 10 分钟空闲超时

max_lifetime = 3600, -- 1 小时最大生命周期

}适用场景:

并发请求 10-50QPS 100-1000查询响应时间 < 500ms高负载应用(大型 API 服务)local pool = mysql.open {

addr = "127.0.0.1:3306",

user = "app_user",

password = "app_password",

database = "mydb",

charset = "utf8mb4",

max_open_conns = 100, -- 最多 100 个并发查询

max_idle_conns = 30, -- 保持 30 个空闲连接

max_idle_time = 300, -- 5 分钟空闲超时(快速释放)

max_lifetime = 3600, -- 1 小时最大生命周期

}适用场景:

并发请求 > 50QPS > 1000需要快速响应注意:确保 MySQL max_connections > 100。

配置优化根据 MySQL 限制调整-- 查询 MySQL 的最大连接数

-- mysql> SHOW VARIABLES LIKE 'max_connections';

-- 假设返回 151

local pool = mysql.open {

addr = "127.0.0.1:3306",

user = "app_user",

password = "app_password",

database = "mydb",

-- 留 20% 余量给其他客户端

max_open_conns = math.floor(151 * 0.8), -- 120

max_idle_conns = 30,

}避免连接浪费-- 不推荐:空闲连接过多

local pool = mysql.open {

max_open_conns = 100,

max_idle_conns = 100, -- ❌ 浪费资源

max_idle_time = 0, -- ❌ 永不超时

}

-- 推荐:合理配置

local pool = mysql.open {

max_open_conns = 100,

max_idle_conns = 20, -- ✅ 保持合理数量

max_idle_time = 300, -- ✅ 5 分钟超时

}动态调整根据监控数据动态调整:

local config = {

low_traffic = {

max_open_conns = 10,

max_idle_conns = 3,

},

high_traffic = {

max_open_conns = 50,

max_idle_conns = 15,

},

}

-- 根据时间或负载切换配置

local current_config = is_peak_hour() and config.high_traffic or config.low_traffic

local pool = mysql.open {

addr = "127.0.0.1:3306",

user = "app_user",

password = "app_password",

database = "mydb",

max_open_conns = current_config.max_open_conns,

max_idle_conns = current_config.max_idle_conns,

}常见问题问题 1:Too many connections错误信息MySQL error: Too many connections (errno: 1040)原因分析应用连接数超过 MySQL 限制

SHOW VARIABLES LIKE 'max_connections';

-- 默认 151连接泄漏:连接未正确关闭

配置不当:max_open_conns 设置过大

解决方案方案 1:增加 MySQL 最大连接数

# 编辑 MySQL 配置文件

sudo vim /etc/mysql/my.cnf

# 添加或修改

[mysqld]

max_connections = 500

# 重启 MySQL

sudo systemctl restart mysql或动态修改(重启后失效):

SET GLOBAL max_connections = 500;方案 2:检查连接泄漏

local silly = require "silly"

local task = require "silly.task"

local mysql = require "silly.store.mysql"

local pool = mysql.open {

addr = "127.0.0.1:3306",

user = "root",

password = "root",

max_open_conns = 10,

}

task.fork(function()

-- ❌ 错误示例:事务连接未关闭

local tx = pool:begin()

tx:query("SELECT 1")

-- 忘记调用 tx:close() 或 tx:commit()

-- 连接泄漏!

end)

task.fork(function()

-- ✅ 正确示例:使用 自动管理

local tx = pool:begin()

tx:query("SELECT 1")

tx:commit()

-- tx 自动关闭,连接归还到池

end)方案 3:降低 max_open_conns

-- 假设有 5 个应用实例

-- MySQL max_connections = 151

-- 每个实例最多:151 / 5 = 30

local pool = mysql.open {

addr = "127.0.0.1:3306",

user = "app_user",

password = "app_password",

max_open_conns = 30, -- 不超过分配数量

}问题 2:连接泄漏检测症状应用运行一段时间后性能下降MySQL 连接数持续增长出现 "Too many connections" 错误检测方法方法 1:监控活跃连接

local silly = require "silly"

local task = require "silly.task"

local time = require "silly.time"

local mysql = require "silly.store.mysql"

local pool = mysql.open {

addr = "127.0.0.1:3306",

user = "root",

password = "root",

database = "test",

}

-- 定期检查连接数

task.fork(function()

while true do

local res = pool:query("SHOW PROCESSLIST")

local conn_count = #res

print(string.format("[%s] 活跃连接数: %d",

os.date("%Y-%m-%d %H:%M:%S"), conn_count))

-- 警告阈值

if conn_count > 100 then

print("⚠️ 警告:连接数过高,可能存在连接泄漏!")

end

time.sleep(10000) -- 每 10 秒检查一次

end

end)方法 2:追踪事务连接

local transaction_counter = 0

-- 包装 pool:begin()

local original_begin = pool.begin

function pool:begin()

local tx, err = original_begin(self)

if not tx then

return nil, err

end

transaction_counter = transaction_counter + 1

local tx_id = transaction_counter

print(string.format("事务 #%d 开始", tx_id))

-- 包装 tx:close()

local original_close = tx.close

function tx:close()

print(string.format("事务 #%d 结束", tx_id))

return original_close(self)

end

return tx, err

end预防措施1. 始终使用 标记

-- ✅ 推荐

task.fork(function()

local tx = pool:begin()

-- 无论是否出错,tx 都会自动关闭

tx:query("UPDATE users SET age = 30 WHERE id = 1")

tx:commit()

end)2. 使用 pcall 保护

task.fork(function()

local tx = pool:begin()

local ok, err = pcall(function()

tx:query("UPDATE users SET age = 30 WHERE id = 1")

tx:query("UPDATE accounts SET balance = 100 WHERE user_id = 1")

tx:commit()

end)

if not ok then

print("事务失败:", err)

tx:rollback()

end

end)3. 设置超时

local pool = mysql.open {

addr = "127.0.0.1:3306",

user = "app_user",

password = "app_password",

max_lifetime = 600, -- 连接最多使用 10 分钟

max_idle_time = 300, -- 空闲 5 分钟后关闭

}问题 3:连接超时错误信息MySQL error: Lost connection to MySQL server during query原因分析网络不稳定:连接被中断查询时间过长:超过 MySQL 超时设置连接空闲太久:超过 wait_timeout解决方案方案 1:增加 MySQL 超时时间

-- 查看当前超时设置

SHOW VARIABLES LIKE '%timeout%';

-- 增加超时时间(8 小时)

SET GLOBAL wait_timeout = 28800;

SET GLOBAL interactive_timeout = 28800;方案 2:使用 ping 检测连接

local silly = require "silly"

local task = require "silly.task"

local mysql = require "silly.store.mysql"

local pool = mysql.open {

addr = "127.0.0.1:3306",

user = "root",

password = "root",

}

-- 查询前先 ping

task.fork(function()

local ok, err = pool:ping()

if not ok then

print("连接已断开:", err.message)

-- 重建连接池

pool:close()

pool = mysql.open {...}

end

-- 执行查询

local res = pool:query("SELECT * FROM users")

end)方案 3:设置合理的连接生命周期

local pool = mysql.open {

addr = "127.0.0.1:3306",

user = "app_user",

password = "app_password",

-- 小于 MySQL wait_timeout(默认 28800 秒)

max_lifetime = 3600, -- 1 小时

max_idle_time = 600, -- 10 分钟

}问题 4:重连机制实现自动重连local silly = require "silly"

local mysql = require "silly.store.mysql"

local DBPool = {}

DBPool.__index = DBPool

function DBPool.new(config)

local self = setmetatable({}, DBPool)

self.config = config

self.pool = mysql.open(config)

self.reconnect_attempts = 0

self.max_reconnect_attempts = 5

return self

end

function DBPool:query(sql, ...)

local max_retries = 3

local retry_delay = 1000 -- 1 秒

for attempt = 1, max_retries do

local res, err = self.pool:query(sql, ...)

if res then

-- 成功,重置重连计数

self.reconnect_attempts = 0

return res, nil

end

-- 检查是否是连接错误

if err and (err.message:match("Lost connection") or

err.message:match("MySQL server has gone away")) then

print(string.format("连接断开,尝试重连 (%d/%d)...",

attempt, max_retries))

-- 尝试重建连接

local ok = self:reconnect()

if ok then

-- 重试查询

time.sleep(retry_delay)

else

break

end

else

-- 其他错误,直接返回

return nil, err

end

end

return nil, {message = "查询失败,已达到最大重试次数"}

end

function DBPool:reconnect()

self.reconnect_attempts = self.reconnect_attempts + 1

if self.reconnect_attempts > self.max_reconnect_attempts then

print("❌ 超过最大重连次数,放弃重连")

return false

end

-- 关闭旧连接池

pcall(function()

self.pool:close()

end)

-- 创建新连接池

local ok, err = pcall(function()

self.pool = mysql.open(self.config)

local res, err = self.pool:ping()

if not res then

error(err.message)

end

end)

if ok then

print("✅ 重连成功")

return true

else

print("❌ 重连失败:", err)

return false

end

end

function DBPool:close()

self.pool:close()

end

local db = DBPool.new {

addr = "127.0.0.1:3306",

user = "root",

password = "root",

database = "test",

}

task.fork(function()

-- 自动处理重连

local res, err = db:query("SELECT * FROM users")

if res then

print("查询成功:", #res)

else

print("查询失败:", err.message)

end

db:close()

end)最佳实践1. 连接生命周期管理应用启动时创建连接池local silly = require "silly"

local mysql = require "silly.store.mysql"

-- 全局连接池(应用启动时创建)

local DB = mysql.open {

addr = "127.0.0.1:3306",

user = "app_user",

password = "app_password",

database = "mydb",

max_open_conns = 20,

max_idle_conns = 5,

}

-- 导出接口

return {

query = function(sql, ...)

return DB:query(sql, ...)

end,

begin = function()

return DB:begin()

end,

close = function()

DB:close()

end,

}应用关闭时优雅关闭local silly = require "silly"

local signal = require "silly.signal"

local mysql = require "silly.store.mysql"

local pool = mysql.open {...}

-- 监听退出信号

signal.signal("INT", function()

print("收到退出信号,正在关闭...")

-- 关闭连接池

pool:close()

print("连接池已关闭")

-- 退出应用

os.exit(0)

end)

print("应用已启动,按 Ctrl+C 退出")2. 事务处理使用 自动管理local silly = require "silly"

local task = require "silly.task"

local mysql = require "silly.store.mysql"

local pool = mysql.open {...}

task.fork(function()

-- 使用 确保事务连接被关闭

local tx = pool:begin()

-- 执行操作

tx:query("UPDATE accounts SET balance = balance - 100 WHERE id = 1")

tx:query("UPDATE accounts SET balance = balance + 100 WHERE id = 2")

-- 提交事务

local ok, err = tx:commit()

if not ok then

print("提交失败:", err.message)

tx:rollback()

end

-- tx 自动关闭

end)事务错误处理local function transfer(from_id, to_id, amount)

local tx, err = pool:begin()

if not tx then

return nil, "无法开始事务: " .. err.message

end

-- 使用 pcall 捕获所有错误

local ok, err = pcall(function()

-- 扣款

local res, err = tx:query(

"UPDATE accounts SET balance = balance - ? WHERE id = ?",

amount, from_id

)

if not res then

error(err.message)

end

-- 到账

res, err = tx:query(

"UPDATE accounts SET balance = balance + ? WHERE id = ?",

amount, to_id

)

if not res then

error(err.message)

end

-- 提交

res, err = tx:commit()

if not res then

error(err.message)

end

end)

if not ok then

tx:rollback()

return nil, err

end

return true

end3. 避免长事务长事务会占用连接,导致其他请求等待。

问题示例-- ❌ 错误:长事务

task.fork(function()

local tx = pool:begin()

-- 大量查询(占用连接很久)

for i = 1, 10000 do

tx:query("INSERT INTO logs VALUES (?, ?)", i, "log message")

end

tx:commit()

end)改进方案方案 1:分批处理

-- ✅ 正确:分批处理

task.fork(function()

local batch_size = 100

for batch = 1, 100 do

local tx = pool:begin()

-- 每批处理 100 条

for i = 1, batch_size do

local id = (batch - 1) * batch_size + i

tx:query("INSERT INTO logs VALUES (?, ?)", id, "log message")

end

tx:commit()

-- 释放连接,让其他请求使用

end

end)方案 2:批量插入

-- ✅ 正确:批量插入

task.fork(function()

local values = {}

for i = 1, 10000 do

table.insert(values, string.format("(%d, 'log message')", i))

end

-- 单条 SQL 插入所有数据

pool:query("INSERT INTO logs VALUES " .. table.concat(values, ","))

end)4. 预热连接池应用启动时预先建立连接,避免第一次请求慢。

local silly = require "silly"

local mysql = require "silly.store.mysql"

local pool = mysql.open {

addr = "127.0.0.1:3306",

user = "app_user",

password = "app_password",

database = "mydb",

max_open_conns = 20,

max_idle_conns = 5,

}

-- 预热连接池

local function warmup_pool(count)

print("正在预热连接池...")

local tasks = {}

for i = 1, count do

table.insert(tasks, task.fork(function()

local ok, err = pool:ping()

if ok then

print(string.format("连接 #%d 就绪", i))

else

print(string.format("连接 #%d 失败: %s", i, err.message))

end

end))

end

-- 等待所有连接建立

for _, task in ipairs(tasks) do

silly.wait(task)

end

print(string.format("连接池预热完成,已建立 %d 个连接", count))

end

-- 预热 5 个连接

warmup_pool(5)

print("应用已启动")监控指标1. 活跃连接数实时监控 MySQL 活跃连接。

local silly = require "silly"

local mysql = require "silly.store.mysql"

local pool = mysql.open {...}

-- 监控活跃连接

task.fork(function()

while true do

local res = pool:query([[

SELECT COUNT(*) as count

FROM information_schema.PROCESSLIST

WHERE User = 'app_user'

]])

if res then

local active_conns = res[1].count

print(string.format("[%s] 活跃连接: %d",

os.date("%H:%M:%S"), active_conns))

-- 告警

if active_conns > 50 then

print("⚠️ 警告:活跃连接过多")

end

end

silly.sleep(5000) -- 每 5 秒检查

end

end)2. 查询等待时间监控查询等待连接的时间。

local function timed_query(pool, sql, ...)

local wait_start = silly.time.now()

-- 执行查询(可能需要等待连接)

local query_start = silly.time.now()

local res, err = pool:query(sql, ...)

local query_end = silly.time.now()

local wait_time = query_start - wait_start

local query_time = query_end - query_start

-- 记录慢等待

if wait_time > 100 then

print(string.format("⚠️ 慢等待: 等待连接 %.2fms", wait_time))

end

-- 记录慢查询

if query_time > 1000 then

print(string.format("⚠️ 慢查询: %.2fms - %s", query_time, sql))

end

return res, err

end

-- 使用

task.fork(function()

local res, err = timed_query(pool, "SELECT * FROM users WHERE id = ?", 1)

end)3. 错误率监控数据库操作的错误率。

local stats = {

total = 0,

success = 0,

error = 0,

}

local function tracked_query(pool, sql, ...)

stats.total = stats.total + 1

local res, err = pool:query(sql, ...)

if res then

stats.success = stats.success + 1

else

stats.error = stats.error + 1

print("查询错误:", err.message)

end

return res, err

end

-- 定期输出统计

task.fork(function()

while true do

silly.sleep(60000) -- 每分钟

if stats.total > 0 then

local error_rate = (stats.error / stats.total) * 100

print(string.format(

"统计: 总计=%d, 成功=%d, 失败=%d, 错误率=%.2f%%",

stats.total, stats.success, stats.error, error_rate

))

if error_rate > 5 then

print("⚠️ 警告:错误率过高")

end

-- 重置统计

stats.total = 0

stats.success = 0

stats.error = 0

end

end

end)4. 完整监控面板local silly = require "silly"

local mysql = require "silly.store.mysql"

local pool = mysql.open {...}

local metrics = {

queries = {total = 0, success = 0, error = 0},

wait_times = {},

query_times = {},

}

-- 包装查询函数

local function monitored_query(sql, ...)

local wait_start = silly.time.now()

local query_start = silly.time.now()

local res, err = pool:query(sql, ...)

local query_end = silly.time.now()

-- 记录指标

metrics.queries.total = metrics.queries.total + 1

if res then

metrics.queries.success = metrics.queries.success + 1

else

metrics.queries.error = metrics.queries.error + 1

end

table.insert(metrics.wait_times, query_start - wait_start)

table.insert(metrics.query_times, query_end - query_start)

-- 保持最近 100 条记录

if #metrics.wait_times > 100 then

table.remove(metrics.wait_times, 1)

end

if #metrics.query_times > 100 then

table.remove(metrics.query_times, 1)

end

return res, err

end

-- 计算平均值

local function average(tbl)

if #tbl == 0 then return 0 end

local sum = 0

for _, v in ipairs(tbl) do

sum = sum + v

end

return sum / #tbl

end

-- 定期输出监控报告

task.fork(function()

while true do

silly.sleep(60000) -- 每分钟

print("\n========== 数据库监控报告 ==========")

print(string.format("时间: %s", os.date("%Y-%m-%d %H:%M:%S")))

print(string.format("查询总数: %d", metrics.queries.total))

print(string.format("成功: %d (%.1f%%)",

metrics.queries.success,

metrics.queries.total > 0 and (metrics.queries.success / metrics.queries.total * 100) or 0

))

print(string.format("失败: %d (%.1f%%)",

metrics.queries.error,

metrics.queries.total > 0 and (metrics.queries.error / metrics.queries.total * 100) or 0

))

print(string.format("平均等待时间: %.2fms", average(metrics.wait_times)))

print(string.format("平均查询时间: %.2fms", average(metrics.query_times)))

print("====================================\n")

-- 重置计数

metrics.queries = {total = 0, success = 0, error = 0}

end

end)

-- 导出接口

return {

query = monitored_query,

}性能调优1. 连接数计算公式根据应用特性计算最佳连接数。

公式max_open_conns = (QPS × 平均查询时间) ÷ 1000 × 安全系数

其中:

- QPS: 每秒查询数

- 平均查询时间: 单位毫秒

- 安全系数: 1.2-1.5(预留余量)示例计算场景 1:简单查询

QPS: 1000平均查询时间: 10ms安全系数: 1.2max_open_conns = (1000 × 10) ÷ 1000 × 1.2 = 12场景 2:复杂查询

QPS: 500平均查询时间: 100ms安全系数: 1.5max_open_conns = (500 × 100) ÷ 1000 × 1.5 = 75实际测量local silly = require "silly"

local mysql = require "silly.store.mysql"

local pool = mysql.open {...}

-- 测试查询性能

local function benchmark()

local total_queries = 1000

local start = silly.time.now()

for i = 1, total_queries do

pool:query("SELECT * FROM users WHERE id = ?", i % 100)

end

local elapsed = silly.time.now() - start

local qps = total_queries / (elapsed / 1000)

local avg_time = elapsed / total_queries

print(string.format("QPS: %.0f", qps))

print(string.format("平均查询时间: %.2fms", avg_time))

-- 计算推荐连接数

local recommended = math.ceil((qps * avg_time) / 1000 * 1.2)

print(string.format("推荐 max_open_conns: %d", recommended))

end

benchmark()2. 批量操作优化批量插入-- ❌ 慢:逐条插入

for i = 1, 1000 do

pool:query("INSERT INTO logs VALUES (?, ?)", i, "message")

end

-- ✅ 快:批量插入

local values = {}

for i = 1, 1000 do

table.insert(values, string.format("(%d, 'message')", i))

end

pool:query("INSERT INTO logs VALUES " .. table.concat(values, ","))批量查询(IN 子句)-- ❌ 慢:逐条查询

local users = {}

for _, id in ipairs(user_ids) do

local res = pool:query("SELECT * FROM users WHERE id = ?", id)

if res and #res > 0 then

table.insert(users, res[1])

end

end

-- ✅ 快:批量查询

local ids = table.concat(user_ids, ",")

local users = pool:query("SELECT * FROM users WHERE id IN (" .. ids .. ")")3. 预处理语句缓存Silly 自动缓存预处理语句,相同 SQL 会复用。

local silly = require "silly"

local mysql = require "silly.store.mysql"

local pool = mysql.open {...}

task.fork(function()

-- 第一次执行:准备语句

pool:query("SELECT * FROM users WHERE id = ?", 1)

-- 后续执行:复用预处理语句(更快)

for i = 2, 1000 do

pool:query("SELECT * FROM users WHERE id = ?", i)

end

end)优化建议:

使用参数化查询(? 占位符)避免动态拼接 SQL相同结构的查询使用相同 SQL-- ❌ 不推荐:无法复用预处理语句

pool:query("SELECT * FROM users WHERE id = " .. id)

-- ✅ 推荐:复用预处理语句

pool:query("SELECT * FROM users WHERE id = ?", id)4. 索引优化确保查询使用索引。

local silly = require "silly"

local mysql = require "silly.store.mysql"

local pool = mysql.open {...}

-- 使用 EXPLAIN 分析查询

task.fork(function()

local sql = "SELECT * FROM users WHERE email = ?"

local res = pool:query("EXPLAIN " .. sql, "user@example.com")

print("查询分析:")

for _, row in ipairs(res) do

print(string.format(" type: %s, key: %s, rows: %d",

row.type, row.key or "NULL", row.rows))

end

-- 检查是否使用索引

if res[1].key == nil then

print("⚠️ 警告:查询未使用索引,考虑添加索引")

print(" 建议: CREATE INDEX idx_email ON users(email);")

end

end)参考资料silly.store.mysql API 参考数据库应用教程MySQL 连接池最佳实践Go database/sql 包设计理念

相关推荐