一条Select语句引发的反思

本文介绍了在使用MySQL命令行工具处理大数据量时遇到的内存溢出问题及其解决方案。通过使用--quick参数,可以避免客户端缓存整个查询结果,从而有效降低内存消耗。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在写一个数据转储的程序,功能是从源数据库读取数据、对数据加工、插入到指定数据库。采用的方式是调用mysql -e 将查询的结果重定向到指定文件。

eg: mysql -hxxx -uxxx -pxxx DatabaseName -e "select * from t_test;" > test

测试过程中:

  • 源数据库的数据量少:

    程序正常运行,没有任何异常

  • 源数据库的数据量大(21G,2亿+条)

    因为在程序中直接调用mysql 来执行,在使用top命令对程序使用的内存进行监控的时候,发现15S,mysql的内存占用量已经达到50%(4核,8G机器)

分析原因:

  • 测试mysqldump命令的内存和CPU占用量

    cpu的占用率为50%左右,内存始终维持在0.1

    • 为什么不用mysqldump命令?

    因为不合适,这里的使用场景之一是将源数据库的指定列都读取出来,加工,插入到目标数据库。mysqldump主要的使用场景是对数据库的复制。

  • mysql命令行直连mysql server测试

    内存升的更快,内存在5S的时候就升到了40%

终极大招——Google+Stackoverflow

  • 烟雾弹

    由于笔者读东西一直是一目十行的,所以在查到https://bugs.mysql.com/bug.php?id=77403这个mysql的bug后就查了下产品预发布和线上的MySQL的版本,哈哈,居然都是5.6(小版本忽略),于是很高兴的跟老板说,这个问题是MySQL的bug。

    老板用来2秒钟大致看了下文档,告诉我这个跟我的问题不一样,解释下这个mysql的bug是有人发现5.5的MySQL升级到5.6.25后发现MySQL Server 的内存使用量暴增,而我的是客户端的内存 使用量暴增。感觉差点想要找一个地缝钻进去,唉,做人还是要认真!!!

  • 正解

    • mysql [options] database

    options中有个–quick的选项,详细解释如下:


    -q, --quick Don't cache result, print it row by row. This may slow
    down the server if the output is suspended. Doesn't use
    history file.

    你以为这就结束了是不是,不,知其然还要知其所以然!

myql –quick命令介绍

以下这部分英语是直接摘自MySQL的英文帮助文档,笔者翻译水平有限,怕翻译有误,所以直接摘录过来。


Out of memory

If you issue a query using the mysql client program and receive an error like the following one, it means that mysql does not have enough memory to store the entire query result:

mysql: Out of memory at line 42, 'malloc.c'
mysql: needed 8136 byte (8k), memory in use: 12481367 bytes (12189k)
ERROR 2008: MySQL client ran out of memory

To remedy the problem, first check whether your query is correct. Is it reasonable that it should return so many rows? If not, correct the query and try again. Otherwise, you can invoke mysql with the --quick option. This causes it to use the mysql_use_result() C API function to retrieve the result set, which places less of a load on the client (but more on the server).


归根节点就是在使用–quick的选项后,会强制调用mysql_use_result() 的函数,我的理解是客户端不会缓存MySQL返回的结果而是直接打印出来,这样就不会撑爆内存。

<think>嗯,用户想用SQL的TRIM函数提取字符串'abcdefg'的最后三个字符'efg'。首先,我需要回忆一下TRIM函数的基本用法。TRIM通常用于去除字符串开头或结尾的特定字符,默认是去除空格。比如TRIM(LEADING 'x' FROM 'xxabcxx')会去掉开头的x,得到'abcxx'。但用户的需求是提取后三位,这似乎和TRIM的常规用法不太一样。 这时候可能需要考虑TRIM的其他参数,比如是否可以使用TRAILING参数,或者结合其他函数。比如,如果字符串末尾有固定的字符,可以用TRIM去掉前面的部分,但'abcdefg'末尾没有重复或特定字符,直接使用TRIM可能不太行。可能需要结合LENGTH函数获取字符串长度,再用SUBSTR或SUBSTRING来截取后三位。但用户特别提到要用TRIM,这可能是个误区,因为TRIM主要功能不是截取子串,而是去除特定字符。 接着,我想到用户提供的示例中,引用了SUBSTR函数的使用,比如substr('abcdefg',-3,4)的结果是'efg'。这说明在Oracle中,SUBSTR的负数位置参数可以从末尾开始计数。但用户可能被误导,认为TRIM可以实现类似功能,或者想寻找不同的方法。 或许用户对TRIM函数的功能理解有误,或者有其他特定场景需要使用TRIM。这时候需要验证TRIM是否真的可以实现截取后三位。经过思考,TRIM函数无法直接指定截取的位置或长度,它只能去除特定字符。因此,正确的做法应该是使用SUBSTR或RIGHT函数,但用户可能因为某些限制必须使用TRIM,这时候可能需要创造性使用函数组合。 比如,先反转字符串,再用TRIM去除前面的部分,然后再反转回来。例如,在MySQL中,可以用REVERSE函数配合SUBSTRING和TRIM,但这种方法比较繁琐,且可能不够直观。或者,使用LENGTH计算长度,再用SUBSTR截取后三位。例如,SUBSTR('abcdefg', LENGTH('abcdefg') - 2, 3)。但用户可能希望用TRIM来实现,可能需要更深入的思考。 另外,查看用户提供的引用,引用[1]提到SUBSTR的负数参数用法,引用[2]和[3]涉及字符函数,引用[4]讨论LEN和DATALENGTH的区别。这些引用中没有提到TRIM用于截取子串,所以用户可能混淆了TRIM和SUBSTR的功能。因此,正确的解决方案应该是使用SUBSTR而不是TRIM,但需要向用户解释这一点,并说明TRIM的局限性。 总结:用户的问题可能源于对TRIM函数功能的误解,正确的做法是使用SUBSTR或RIGHT函数。需要指出TRIM不适合此场景,并提供正确的SQL写法,同时解释为什么TRIM无法实现该需求。</think>根据您的要求,使用TRIM函数直接截取后三位字符存在困难,但可以通过组合函数实现类似效果。不过需要说明:**TRIM函数主要用于删除首尾特定字符**,常规用法无法直接截取子串。建议优先使用SUBSTR/RIGHT函数实现该需求[^1][^3]。 ### 方案一:使用RIGHT函数(推荐) ```sql SELECT RIGHT('abcdefg', 3) FROM dual; -- 结果: efg ``` ### 方案二:使用SUBSTR函数(兼容Oracle语法) ```sql SELECT SUBSTR('abcdefg', -3) FROM dual; -- 结果: efg ``` ### 方案三:强制使用TRIM的变通方法(仅特定场景有效) 若必须使用TRIM函数,需要结合字符串反转和截取: ```sql SELECT REVERSE( SUBSTR( REVERSE('abcdefg'), 1, 3 ) ) FROM dual; -- 结果: efg ``` ### TRIM函数详解 标准语法:`TRIM([LEADING|TRAILING|BOTH] trim_character FROM source_string)` 例如删除尾部数字:`SELECT TRIM(TRAILING '123' FROM 'abc123') FROM dual;` 该函数**无法直接截取指定位置字符**,只能移除首尾匹配字符[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值