读书忌死读,死读钻牛角。——叶圣陶
1 orm和mysql字段的长度
sqlalchemy 用model创建表之后 如果你指定了varchar的长度是20 那么第一次用orm生成表的时候length=20 但是当你插入21个字符的时候 报错pymysql.err.DataError: (1406, "Data too long for column 'name' at row 1")。我们修改mysql字段长度到25 再次插入21个字符 但是记住我们并没有修改model的长度 也就是说model还是20字符长,我们最后发现成功插入数据库表中。
结论
model中varchar的长度只是第一次创建表的时候有用,后面只要通过mysql表字段去修改了,即使model varchar不修改,也没有问题。当然如果表字段varchar改为text也没有问题 即使数据库表字段是varchar。
2 数据库引擎没有设置超时
2.1 背景
我们发现,各个子页面都会调用大数据一个查询DB的操作,而这个数据大概是8千万。我们的sqlalchemy session查询非常耗时,大概50s左右,但是后来又满满好了,查询在1s左右。为了重现线上的问题我们做一下分析
2.2 分析
其实有时候我们遇到这样的问题,首先想到的就是优化查询,比如通过explain看看有没有命中索引啊,是否用到文件排序或者说回表查询啊,这种思路挺对的,你也必须过一遍,过完之后发现你的查询很NB,没什么问题,那这个时候我们就要站在更高的角度去看待问题,不要死死盯着你的sql,因为你再怎么优化无济于事。
考虑到是大数据环境,偶尔查询慢是正常的,因为有很多因素,比如带宽啊,网络啊以及负载啊之类的。所以我们怀疑如果这些因素导致我们查询慢,一定是我们那里没有设置超时时间导致sql变慢的,后来追溯源码,发现引擎底层是支持read_timeout的,而我们代码中在创建连接的时候并没有指定,因此必须立刻马上现在解决它。
2.3 解决
但是线上数据都是1s左右返回,如何线下模拟呢?
解决方案:锁表
先在创建engin的时候传入参数
比如
创建engine的时候,设置参数connect_args={"read_timeout":5} .这样创建的engine就会在读取数据超时的情况下抛出超时异常。
再把整个表以write的方式锁住,这样其他session就没办法查询或者修改,直到锁释放才会执行,否则会一直阻塞。这样我们就可以解决超时的现象。
我们先开启一个session会话,比如mysql终端。然后lock table big_data write; 然后我们程序启动,自然开启session去执行big_data的查询。这样等待5s之后抛出异常,完美还原案发现场。
最后unlock tables
3 小结
有时候大家碰到问题,要经常汇总和整理,这样下次遇到类似问题直接找出来用,当你累积到一定程度,那么像这样的问题其实就是自然而然的解决了。
4 关注公众号
微信公众号:堆栈future