几百条数据的表里,sql偶尔出现执行达到1秒
几百条数据的表,字段也很少,sql也很简单,sql偶尔出现执行达到1秒。 数据库是mysql 8,本地测试环境(docker 部署的mysql)没有这个问题,阿里云的rds有这个问题,下面是两个例子。
guid:_,freesql 执行耗时732毫秒:
SELECT a.ChildId, a.LastCalcGameScoreDate
FROM ChildFlag a
WHERE (a.LastCalcGameScoreDate < '2022-07-22 00:00:00.000')
limit 0,1,
guid:_,freesql 执行超过983毫秒:
SELECT a.PID, a.Mobile, a.AccountId, a.First_Name, a.City, a.Profile_Image, a.Active, a.LastLoginTime, a.JoinDate, a.Server_Lock, a.IpAddress, a.InfoStatus, a.ChildCount
FROM ParentInfo a
WHERE (a.AccountId = 445)
limit 0,1,
连接串设置 min pool size=1
好的,我试试,谢谢
Min Pool Size=100 é®é¢è¿æ¯åå¨

è¿ä¸ªè¡¨åªæ458æ¡æ°æ®ï¼3ä¸ªåæ®µ
CREATE TABLE childflag (
ChildId int NOT NULL,
LastScreenTimeCalcPointDate date DEFAULT NULL,
LastCalcGameScoreDate date NOT NULL DEFAULT '0001-01-01'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
试试单独 new mysqlconnection().open 执行要多久
嗯,因为是偶现的,所以直接记录这个时间耗时不长的,我在耗时长时加了这个测试,等出现这种情况时看耗时

open耗时0毫秒,在高耗时sql发生时调用的
fsql.Aop.CommandAfter += (_, e) => { if (e.耗时 > 500) Console.WriteLine(e.Log); };
记录一下详细信息
好的,已经加了,有结果了发上来,感谢
昨天没重现出来,今天出来了,有两条超时的
CommandAfter耗时589毫秒:FreeSql: Master Database(执行SQL)语句耗时过长588.3405ms
SELECT a.`ChildId`, a.`LastCalcGameScoreDate`
FROM `ChildFlag` a
WHERE (a.`LastCalcGameScoreDate` < '2022-07-27 00:00:00.000')
limit 0,1
PrepareCommand: 0.0119ms Total: 0.0174ms
Pool.Get: 0.0009ms Total: 0.0209ms
ExecuteReader: 588.3091ms Total: 588.3383ms
CommandAfter耗时596毫秒:FreeSql: Slave Database1(执行SQL)语句耗时过长596.6055ms
SELECT a.`Id`, a.`CateName`, a.`IsOnline`, a.`OnlineTime`, a.`OfflineTime`, a.`IsDelete`, a.`IsHelp`, a.`OrderNum`
FROM `cms_article_cate` a
WHERE (a.`IsDelete` = 0 AND a.`IsOnline` = 1 AND a.`IsHelp` = 0)
ORDER BY a.`OrderNum` DESC
PrepareCommand: 0.0181ms Total: 0.0272ms
Pool.Get: 595.2237ms Total: 595.2557ms
ExecuteReader: 1.3417ms Total: 596.6007ms
Pool.Return: 0.0027ms Total: 596.6047ms
Pool.Get: 595.2237ms Total: 595.2557ms
消耗在 MySqlConnection Open 方法
但是加了Min Pool Size=100,系统访问量很少,不会超过100
两条好像还不一样,ExecuteReader耗时长是数据库的问题吗
Min Pool Size 只代表首次预热,网络连接不一定是本地保持,也有可能服务端主动断开,即使提前创建了 100 个连接,但他们不一定全都是活跃,活跃的意思是每个连接 30 秒之类一定会有下次操作,这个阀值超过服务器设置,就会被服务端主动断开连接,此时客户端是不知道的。
对于此种情况,客户端也会做一套检测程序,当某连接超过 30 秒或者设置的 Connection Lifetime,也会强制断开连接,重新 new MySqlConnection() Open
如果想保持连接不断开,应该加大数据库访问,以免被客户端或者服务端触发【不活跃】的机制断开物理连接。
如果本身访问量不大,min pool size 不需要设置 100 这么大。
看了下源码现在连接池里的连接是通过堆栈来保存的,如果这样是不是通过队列会更好点,每个连接都会循环使用到,就可以避免一个连接长时间未使用的情况,否则长时间访问不大时堆栈底部的连接是一直用不到的,一旦并发突然上来,底部连接拿出来用就会有这个问题。
看来下csredis好像也是这个逻辑,之前也提过连接不可用的情况,或许改成队列也可以避免
队列有一个问题
[0] [1] [2] 当获取到这里过期,后面的全部都过期了,每次都 new open [3] [4] ... [N]
早期已经尝试过队列,后来才改成的栈结构
"当获取到这里过期,后面的全部都过期了,每次都 new open" 这个没明白, 入》9,8,7,6,5,4》出 获取到4时如果4是过期的,下一个5不一定是过期的吧,5是比4更晚进入队列的,所以是空闲时间更短的
我觉得很有可能是网络问题。
我尝试过内网不同机器装同样的库,A 机器工作了几个月很正常,但是某天无故操作很慢,慢到打开一个连接都需要十多秒,就算我重装库,问题依旧。于是通过 B 机器安装,一切正常。差不多又过了几个月,无意中又发现 A 机器又完全正常了。
不能说阿里系统存在问题,所以我觉得问题更多再网络连接上
"当获取到这里过期,后面的全部都过期了,每次都 new open" 这个没明白, 入》9,8,7,6,5,4》出 获取到4时如果4是过期的,下一个5不一定是过期的吧,5是比4更晚进入队列的,所以是空闲时间更短的
队列是前进前出,你比喻成栈了
是不是网络防火墙设置超时问题导致的。