前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一条SQL能占多大内存?

一条SQL能占多大内存?

作者头像
Lenis
发布2021-07-05 14:42:01
2.2K0
发布2021-07-05 14:42:01
举报
文章被收录于专栏:有关SQL有关SQL

初学计算机时,我经常琢磨的一个问题是:一个进程到底能吃多大内存,能把系统内存吃完?

学了数据库后,我又开始问自己类似的问题,一条 SQL 能把数据库内存全部吃完?

假设数据库系统内存 有128GB,全盘扫描一遍 200GB的表,是不是就把数据库内存撑爆了,别人的 SQL 就不能运行了?

一开始,这个问题我始终没找到答案。

经过零零散散学了些数据库系统知识,最终把这些零碎的知识拼凑起来,完整呈现一条SQL请求发给数据库,数据库到底怎么层层运转,最终把数据吐给最初的请求(客户端)后,我才不迷惑了!

这是一条粗的数据流转链路,实际上,单看这条链路,总以为(结果集)数据是一下撑到内存里,接着由内存发到请求客户端。实际上,并不总是这样。

下面用SQL Server 的导出数据做演示。虚拟机服务器总共有8G内存,从数据库导出一张2GB的表,监测服务器内存的使用量。

1- 用 SQL Server 自带的“导出”功能,将一张2GB的表,导出到一个文本文件。为了不影响虚拟机中内存的监控,这个导出的操作, 在本机(架设虚拟机的本地机器)执行。

2 - 在服务器上,打开系统监控窗口,监控每秒钟的服务器内存使用量:

在开始测试之前,设置数据库的最大可用内存为 2GB. 否则系统容易出现OOM(Out Of Memory)的错误。

在SQLServer中,设置系统可用最大的内存,可以用以下命令:

代码语言:javascript
复制

  execute sp_configure 'max server memory'  ,2048
  reconfigure with override
  

以上把 SQL Server 服务器最大可用内存设置为 2048MB,即2GB.

设置完后,当启动 2 个抽取数据的任务后,SQL Server 占用系统的内存比率,变得恒定。

那么如果不设置这个值,会有什么影响?

来做一次实验,把最大可用内存扩大10倍:

代码语言:javascript
复制

  execute sp_configure 'max server memory'  ,20480
  reconfigure with override
  

再启动 2个抽取数据的任务, 可得系统内存的比率图:

如果内存全部耗完,整个操作系统变得不稳定,SQL Server 的稳定性即即将崩溃。

回到主问题,一条 SQL 能占多大内存?

代码语言:javascript
复制
select
 sess.host_name,
 sess.program_name,
 sess.client_interface_name,
 sess.login_name,
 sess.status,
 sess.cpu_time,
 sess.memory_usage,
 sess.total_scheduled_time,
 sess.total_elapsed_time,
 sess.reads,
 sess.writes,
 sess.text_size,
 sess.row_count,
 sess.page_server_reads ,
 sql_text.text as sql_text
from
 sys.dm_exec_sessions sess
inner join sys.dm_exec_connections sql_con
 on sql_con.session_id = sess.session_id 
cross apply (
 select
  text
 from
  sys.dm_exec_sql_text(sql_con.most_recent_sql_handle) t) sql_text
where sess.host_name = 'DESKTOP-15RCMQD' and client_interface_name='OLEDB'



着重看这个数字:sys.dm_exec_session.memory_usage.

特别的是,4 看上去直观,但意义非凡。在 SQL Server 中 memory_usage 以page为计量单位。

在sql server中默认的一个 page 能存 8K数据, memory_usage 等于4,意味着总共使用了 32KB的数据。

看到这,有疑惑是这样的。导出 5000 万条数据,共 2.2GB 数据,只用了32KB内存?

事实上,这里可以用码头跑船来形容。

在魔都(上海)的朋友,可能去码头玩过。一艘艘跑船,打通了国际航运。普通货船吨位在1万吨,如果要把马来西亚10万吨的香蕉运到上海,需要10个来回。

数据库在导数据时,也一样。

比如 5000万的数据,一个批次只能运输 10000 条,那总共就该分成 5000个批次来回导。

但正如跑船业务,我的船载重大,别的船1万吨,我的船吃重10万吨,别人跑10次,我跑1次。

所以数据库在导入导出数据时,也可以据量派船。数据量大,就把数据包缓存加大;反之,就用恒定量的数据包。但修改数据包缓存属性会造成更多麻烦,除非能掌控全局影响,轻易不修改。

在进行导出操作时,查询系统字典表,不难发现,大数据量导出的这条链接,一直处于活动状态,显示等待客户端处理, 等待类型为 ASYNC_NETWORK_IO

这里又引出一个问题,假设这个链接一直处于活动状态,本该共享的数据库链接就会一直被占用,导致其他用户不能操作数据库,也就是,降低了并发量。

这,是数据库链接池的范畴。

数据库库链接池的建立,旨在提高数据库的访问效率。建立一条数据库链接,最大的代价是耗时,比如审核权限,分配链接内存,加入请求栈等。

每次与数据库的交互,多等1秒,对用户体验就十分不友好。解决方法,是系统在预加载的时候,多建立几个链接,等到用时,把已经建立好的链接拿过来就用,这样就可省去建链接的时间。

既然说到可以预先建立几个数据库链接备用,那么是不是建的越多越好,比如100万个?真的不是

设置的越大,反而还有风险。100万个数据库链接同时跑起来,对CPU的时间分片也是压力,CPU的数量是恒定的,比如8核。同时处理8个任务是最好的利用,一旦同时处理80个任务,CPU的分时分片就不可避免,每个任务就会有等待。这样CPU频繁切换任务,会导致任务一个都处理不完。

就好比,本来你一天看一本书,会沉浸在意识流中,效率很高,神情也很饱满,一旦你开始一天同时读三本书,且都想读完时,就变得非常焦虑。事实上,临睡前,你可能 一本都读不完。

所以,数据库连接池针对长短链接,一定要分级控制。该长的链接,就不能让它频繁切换。该短的链接,就不能让它长期占着,降低并发

--完--

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-06-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 有关SQL 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档