数据库系列之MySQL数据库中内存使用分析

news2024/11/24 14:59:48

在实际系统环境中,MySQL实例的内存使用随着业务的增长缓慢增长,有些时候并没有及时的释放。本文简要介绍下MySQL数据库中和内存相关的配置,以及分析内存的实际使用情况,以进行应急和调优处理。


1、MySQL内存结构

在MySQL中内存的占用主要由两部分组成:全局共享缓存global buffers和所有线程独立缓存thread buffers。

  • Global buffers主要用于缓存数据页、索引页、数据字典等常用数据,这部分为常驻内存;
  • Thread buffers针对每个数据库连接会话会独立分配缓存,thread buffer与连接数成正比,连接数越高则总的thread buffers占用越高。这部分缓存通常会随着连接的释放而关闭。

MySQL中使用的内存大小等于全局共享缓存(Sharing+innodb_buffer_pool)和所有线程缓存之和,如下图所示:

在这里插入图片描述

1)global_buffers:包括Sharing buffers部分+InnoDB_Buffer_Pool

  • innodb_buffer_pool_size:InnoDB高速缓存,缓存innodb表的索引,数据,插入数据时的缓冲,以及事务锁、自适应哈希等。通过“show engine innodb status \G”和“show global status like ‘innodb_buffer_pool_%’”可以查看innodb_buffer_pool的表现。
  • innodb_log_buffer_size:InnoDB REDO日志缓冲,提高REDO日志写入效率。由于InnoDB在事务提交前,并不将改变的日志写入到磁盘中,因此在大事务中,可以减轻磁盘I/O的压力。
  • innodb_additional_mem_pool_size :用来存放Innodb的内部目录,由系统自动调整。
  • key_buffer_size:指定索引缓冲区的大小,它决定MyISAM表索引处理的速度,尤其是索引读的速度,只对MyISAM表起作用。即使不使用MyISAM表,但是内部的临时磁盘表是MyISAM表,也要使用该值。
  • query_cache_size:查询高速缓存,缓存查询结果,当打开时候,执行查询语句会进行缓存,读写都会带来额外的内存消耗,下次再次查询若命中该缓存会立刻返回结果。
  • table_open_cache:表空间文件描述符缓存,提高数据表打开效率。存放当前已经打开的表句柄,与表创建时指定的存储引擎相关。当把table_open_cache设置的过大时,如果系统处理不了这么多文件描述符,那么就会出现客户端失效、连接不上。
  • table_definition_cache:表定义文件描述符缓存,提高数据表打开效率。MySQL需要打开frm文件,并将其内容初始化为Table Share对象。这里存放与存储引擎无关的,独立的表定义相关信息。

2)all_thread_buffers:max_threads(当前活跃连接数) * (会话级内存分配总和)

  • read_buffer_size:顺序读缓冲,提高顺序读效率。MySQL读入缓冲区的大小,将对表进行顺序扫描的请求将分配一个读入缓冲区,MySQL会为它分配一段内存缓冲区,read_buffer_size变量控制这一缓冲区的大小,如果对表的顺序扫描非常频繁,并你认为频繁扫描进行的太慢,可以通过增加该变量值以及内存缓冲区大小提高其性能。
  • read_rnd_buffer_size:随机读缓冲,提高随机读效率。MySQL的随机读缓冲区大小,当按任意顺序读取行时(列如按照排序顺序)将分配一个随机读取缓冲区,进行排序查询时,MySQL会首先扫描一遍该缓冲,以避免磁盘搜索,提高查询速度,如果需要大量数据可适当的调整该值,但MySQL会为每个客户连接分配该缓冲区所以尽量适当设置该值,以免内存开销过大。
  • sort_buffer_size:排序缓冲,提高排序效率。connection级参数,在每个connection第一次需要使用这个buffer的时候,一次性分配设置的内存。
  • join_buffer_size:表连接缓冲,提高表连接效率。MySQL在完成某些Join需求的时候(all/index join),为了减少参与Join的“被驱动表”的读取次数以提高性能,需要使用到Join Buffer来协助完成 Join操作。
  • binlog_cache_size:二进制日志缓冲,提高二进制日志写入效率为每个session 分配的内存,在事务过程中用来存储二进制日志的缓存,作用是提高记录bin-log的效率。
  • tmp_table_size:内存临时表,提高临时表存储效率。当需要做类似group by操作生成的临时表大小,提高联接查询速度的效果,调整该值直到created_tmp_disk_tables/created_tmp_tables*100% <= 25%。
  • thread_stack:线程堆栈,暂时寄存SQL语句/存储过程、线程运行时的信息等。每个连接线程被创建时,MySQL给它分配的内存大小。当MySQL创建一个新的连接线程时,需要给它分配一定大小的内存堆栈空间,以便存放客户端的请求的Query及自身的各种状态和处理信息。
  • thread_cache_size:线程缓存,降低多次反复打开线程开销。当客户端断开之后,服务器处理此客户的线程将会缓存起来以响应下一个客户而不是销毁(前提是缓存数未达上限)。
  • net_buffer_length:线程持连接缓冲以及读取结果缓冲。客户发出的SQL语句期望的长度,如果语句超过这个长度,缓冲区自动地被扩大,直到max_allowed_packet个字节。
  • bulk_insert_buffer_size:MyISAM表批量写入数据缓冲。如果进行批量插入,可以增加bulk_insert_buffer_size变量值的方法来提高速度,只对myisam表使用。

调整对应的配置后,相应的内存使用大小可以通过计算得到(参考网址http://www.mysqlcalculator.com/):

在这里插入图片描述

另外,也可以通过SQL语句获得各个配置的大小(假设最大连接为200),如下所示:

select VARIABLE_NAME,VARIABLE_VALUE/1024/1024 MB from performance_schema.global_variables WHERE VARIABLE_NAME in ('key_buffer_size','query_cache_size','tmp_table_size','innodb_buffer_pool_size','innodb_additional_mem_pool_size','innodb_log_buffer_size')
union all
SELECT 'sort_buffer_size',(v1.VARIABLE_VALUE*v2.vv) MB
FROM ( select 200 as VARIABLE_VALUE from performance_schema.global_variables WHERE VARIABLE_NAME='MAX_CONNECTIONS' ) AS v1,
  ( SELECT VARIABLE_VALUE/1024/1024 vv FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'sort_buffer_size' ) AS v2 
union all
SELECT 'read_buffer_size',(v1.VARIABLE_VALUE*v2.vv) MB
FROM ( select 200 as VARIABLE_VALUE from performance_schema.global_variables WHERE VARIABLE_NAME='MAX_CONNECTIONS' ) AS v1,
  ( SELECT VARIABLE_VALUE/1024/1024 vv FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'read_buffer_size' ) AS v2 
union all
SELECT 'read_rnd_buffer_size',(v1.VARIABLE_VALUE*v2.vv) MB
FROM ( select 200 as VARIABLE_VALUE from performance_schema.global_variables WHERE VARIABLE_NAME='MAX_CONNECTIONS' ) AS v1,
  ( SELECT VARIABLE_VALUE/1024/1024 vv FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'read_rnd_buffer_size' ) AS v2 
union all
SELECT 'join_buffer_size',(v1.VARIABLE_VALUE*v2.vv) MB
FROM ( select 200 as VARIABLE_VALUE from performance_schema.global_variables WHERE VARIABLE_NAME='MAX_CONNECTIONS' ) AS v1,
  ( SELECT VARIABLE_VALUE/1024/1024  vv FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'join_buffer_size' ) AS v2 
union all
SELECT 'thread_stack',(v1.VARIABLE_VALUE*v2.vv) MB
FROM ( select 200 as VARIABLE_VALUE from performance_schema.global_variables WHERE VARIABLE_NAME='MAX_CONNECTIONS' ) AS v1,
  ( SELECT VARIABLE_VALUE/1024/1024 vv FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'thread_stack' ) AS v2 
union all
SELECT 'binlog_cache_size',(v1.VARIABLE_VALUE*v2.vv) MB
FROM ( select 200 as VARIABLE_VALUE from performance_schema.global_variables WHERE VARIABLE_NAME='MAX_CONNECTIONS' ) AS v1,
  ( SELECT VARIABLE_VALUE/1024/1024 vv FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'binlog_cache_size' ) AS v2

对于连接配置,可以查看系统中历史最大连接情况进行评估

mysql> show global status like 'Max_used_connections';
+----------------------+-------+
| Variable_name        | Value |
+----------------------+-------+
| Max_used_connections | 28    |
+----------------------+-------+
1 row in set (0.00 sec)
2、MySQL中内存相关表

在MySQL中有内存相关的表监控内存的使用情况

mysql> show tables like '%memory%';
+-----------------------------------------+
| Tables_in_performance_schema (%memory%) |
+-----------------------------------------+
| memory_summary_by_account_by_event_name |
| memory_summary_by_host_by_event_name |
| memory_summary_by_thread_by_event_name |
| memory_summary_by_user_by_event_name |
| memory_summary_global_by_event_name |
+-----------------------------------------+
5 rows in set (0.00 sec)

以上表的监控统计,分别统计帐户、主机、线程、用户和全局事件执行内存操作等信息。

1)memory_summary_by_account_by_event_name

按MySQL账户和事件名称分类的内存使用情况摘要,识别哪些账户正在使用最多的内存,以及这些内存是如何分配的,如查询、系统锁等特定事件。

select USER, HOST, EVENT_NAME, SUM_NUMBER_OF_BYTES_ALLOC from performance_schema.memory_summary_by_account_by_event_name order by SUM_NUMBER_OF_BYTES_ALLOC desc limit 10;

2)memory_summary_by_host_by_event_name

按连接到MySQL的主机和事件名称分类的内存使用情况摘要,用来识别识别哪些远程主机或IP地址正在消耗最多的内存。

select HOST, EVENT_NAME, SUM_NUMBER_OF_BYTES_ALLOC from performance_schema.memory_summary_by_host_by_event_name order by SUM_NUMBER_OF_BYTES_ALLOC desc limit 10;

3)memory_summary_by_thread_by_event_name

按MySQL线程ID和事件名称分类的内存使用情况摘要,对于特定的长时间运行查询或事务的内存使用情况特别有用,因为每个线程通常与一个特定的查询或事务相关联。

select thread_id, event_name, SUM_NUMBER_OF_BYTES_ALLOC from performance_schema.memory_summary_by_thread_by_event_name order by SUM_NUMBER_OF_BYTES_ALLOC desc limit 10;

得到thread_id后,查找performance_schema.threads表获得对应的processlist_id和processlist_info:

mysql> select * from performance_schema.threads where THREAD_ID=49\G
*************************** 1. row ***************************
          THREAD_ID: 49
               NAME: thread/sql/one_connection
               TYPE: FOREGROUND
     PROCESSLIST_ID: 10
   PROCESSLIST_USER: root
   PROCESSLIST_HOST: tango-DB01
     PROCESSLIST_DB: tango
PROCESSLIST_COMMAND: Query
   PROCESSLIST_TIME: 84
  PROCESSLIST_STATE: User sleep
   PROCESSLIST_INFO: select count(1),sleep(2000) from tango.t2 for update
   PARENT_THREAD_ID: NULL
               ROLE: NULL
       INSTRUMENTED: YES
            HISTORY: YES
    CONNECTION_TYPE: SSL/TLS
       THREAD_OS_ID: 1657
     RESOURCE_GROUP: USR_default
1 row in set (0.00 sec)

也可以通过THREAD_ID,查找performance_schema.events_statements_current和performance_schema.events_statements_history获得对应的历史记录信息,定位到具体的SQL语句信息,以后续应急或优化。

4)memory_summary_by_user_by_event_name

按MySQL用户和事件名称分类的内存使用情况摘要,更侧重于基于用户名而不是完整的账户信息(包括主机)的内存使用。

select USER, EVENT_NAME, SUM_NUMBER_OF_BYTES_ALLOC from performance_schema.memory_summary_by_user_by_event_name order by SUM_NUMBER_OF_BYTES_ALLOC desc limit 10;

5)memory_summary_global_by_event_name

包括全局的、不按任何特定账户、主机、线程或用户分类的内存使用情况摘要,提供整个MySQL服务器内存使用的概览,并允许按事件名称来查看这些内存是如何分配的。

select event_name, SUM_NUMBER_OF_BYTES_ALLOC from performance_schema.memory_summary_global_by_event_name order by SUM_NUMBER_OF_BYTES_ALLOC desc LIMIT 10;
3、MySQL内存分配管理

MySQL的内存虽然划分为sharing buffers+innodb_buffer_pool和thread buffers,但实际上是按照Server层和innodb层进行内存管理,而且这两部分是按照不同的内存管理方式进行管理的。

  • InnoDB层则主要由Free List、LRU List、FLU List等多个链表来统一管理Innodb_buffer_pool。Innodb_buffer_pool内存初始化是通过「mmap()」方式直接向操作系统申请内存,最终会申请Innodb_buffer_pool_size大小的文件映射段动态内存。「mmap()」方式申请的内存会在文件映射段分配内存,而且在释放时会直接归还系统。这部分内存空间初始化后仅仅是虚拟内存,等真正使用时,才会分配物理内存。
  • Server层是由mem_root来进行内存管理,包括Sharing与Thead buffers。「mem_root」结构体使用内存分配管理器进行内存统一管理,避免频繁调用内存操作,提升性能,统一的分配和管理内存也可以防止发生内存泄漏。

MySQL首先通过「init_alloc_root」函数初始化一块较大的内存空间,实际上最终是「通过malloc函数向内存分配器申请内存空间」,然后每次再调用alloc_root函数在这块内存空间中分配出内存进行使用,其目的就是将多次零散的malloc操作合并成一次大的malloc操作,以提升性能。

在Linux中常用的内存分配管理器有三种:ptmalloc(Glibc)、tcmalloc(Google)、jemalloc(FreeBSD)。MySQL 默认使用的是glibc的ptmalloc作为内存分配器。

  • ptmalloc(glibc):ptmalloc是GNU C库(glibc)中的默认内存分配器,广泛用于Linux系统。它提供了一套标准的内存分配和释放函数,如malloc、free、realloc等。ptmalloc通过维护内存池来优化内存分配,并尝试减少内存碎片。然而,由于它是glibc的一部分,因此在某些情况下,其性能可能不如其他专为性能而设计的内存分配器。
  • tcmalloc(Google):tcmalloc用于多线程环境,并通过减少锁的竞争和内存碎片来提高性能。tcmalloc使用线程本地缓存(Thread-Caching Malloc)的概念,将内存分配的任务分散到不同的线程中,以减少对共享数据结构的竞争。此外,tcmalloc还采用了一些优化策略,如小对象合并、高效的分配器缓存等,以进一步提高性能。
  • jemalloc(FreeBSD):jemalloc是由FreeBSD社区开发的一款通用的内存分配器,并逐渐被其他系统广泛采用。jemalloc的设计目标是提供高度可扩展性和低碎片化的内存分配。它使用了一种称为arena的并发数据结构来管理内存,每个arena都有自己的内存池和缓存,以减少锁的竞争。jemalloc还采用了一种称为“大小类”(size classes)的机制来管理不同大小的内存分配请求。它将内存分配请求划分为不同的大小类,并为每个大小类维护一个独立的内存池和缓存。这种机制使得jemalloc在处理不同大小的内存分配请求时具有更高的灵活性和效率。

在这里插入图片描述

在实际生产系统中,遇到MySQL实例实际占用的内存比innodb_buffer_pool配置的高很多,但是没有及时释放的现象。大部分是因为内存分配管理器占用很多内存不释放,另一部分是因为内存碎片。另外在部分场景下,原生的MySQL使用的ptmalloc内存管理存在内存释放不及时的问题,所以在基于MySQL系列的国产数据库在内存管理上进行了部分优化,比如使用tcmalloc替代ptmalloc进行内存管理。通过以下命令,也可以查看实际使用的内存管理方式:

pt-mysql-summary  -S /tmp/mysql.sock --user root --password xxxxxx|grep -A 5 "Memory management"
# Memory management library ##################################
jemalloc is not enabled in mysql config for process with id 1339
# The End ####################################################

针对ptmalloc(glibc)内存管理的缺陷(调用glibc申请的内存使用完毕后,归还给OS时没有被正常回收,而变成了碎片,随着碎片的不断增长,就能看到mysqld进程占用的内存不断上升)。在测试环境,可以调用gdb函数主动回收释放内存碎片空间:

gdb --batch --pid `pidof mysqld` --ex 'call malloc_trim(0)'

以上是MySQL数据库内存配置和管理的相关知识。


参考资料:

  1. https://dev.mysql.com/doc/refman/8.0/en/memory-use.html
  2. https://blog.csdn.net/dc666/article/details/78901341
  3. https://blog.csdn.net/n88Lpo/article/details/126925517/
  4. https://zhuanlan.zhihu.com/p/264916825
  5. https://www.modb.pro/db/60336

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1689638.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

运营抖音小店,这件事情每天都需要去做!一个都不能少!

大家好&#xff0c;我是电商小V 咱们的店铺开好之后&#xff0c;然后运营自己的店铺每天需要做好什么事情呢&#xff1f;这个问题是很多新手小伙伴开通抖店之后最关心的问题&#xff0c;咱们今天就来详细的说一下运营抖音小店每天需要做什么呢&#xff1f; 第一点&#xff1a;奖…

Transformer详解常见面试问题

文章目录 1. 各模块解决1.1 输入部分1.2 多头注意力&#xff08;作者使用8个头&#xff09;1.3 残差和LayerNorm1.4 Decoder部分 2.Transformer经典问题2.1 tranformer为何使用多头注意力机制&#xff1f;2.2 Transformer相比CNN的优缺点2.3 Encoder和decoder的区别&#xff1f…

03-ArcGIS For JavaScript结合ThreeJS功能

ArcGIS For JavaScript结合ThreeJS功能 概述three.js中功能实现externalRenderers&#xff08;4.28及以下版本&#xff09;RenderNode&#xff08;4.29版本&#xff09; 概述 ArcGIS For Javacript提供了一些对象可以支持加载webgl上下文信息&#xff0c;这里包括webgl编程的代…

【Crypto】Url编码

文章目录 Url编码解题感悟 Url编码 Url编码 搞定 小小flag&#xff0c;拿下&#xff01; 解题感悟 有点饿了…

Edge浏览器:重新定义现代网页浏览

引言 - Edge的起源与重生 Edge浏览器&#xff0c;作为Microsoft Windows标志性的互联网窗口&#xff0c;源起于1995年的Internet Explorer。在网络发展的浪潮中&#xff0c;IE曾是无可争议的霸主&#xff0c;但随着技术革新与用户需求的演变&#xff0c;它面临的竞争日益激烈。…

【加密与解密(第四版)】第十六章笔记

第十六章 脱壳技术 16.1 基础知识 壳的加载过程&#xff1a;保存入口参数、获取壳本身需要使用的API地址、解密原程序各个区块的数据、IAT的初始化、重定位项的处理、HOOK API、跳转到程序原入口点 手动脱壳步骤&#xff1a;查找真正的入口点、抓取内存映像文件、重建PE文件&…

【全网最全】2024电工杯数学建模B题问题一14页论文+19建模过程代码+py代码+2种保奖思路+数据等(后续会更新成品论文等)

您的点赞收藏是我继续更新的最大动力&#xff01; 一定要点击如下的卡片链接&#xff0c;那是获取资料的入口&#xff01; 【全网最全】2024电工杯数学建模B题问一论文19建模过程代码py代码2种保奖思路数据等&#xff08;后续会更新成品论文等&#xff09;「首先来看看目前已…

Python导入Shapefile到PostGIS的常见问题和解决方案

导入Shapefile到PostGIS的常见问题和解决方案 先决条件&#xff1a; 已经拥有含有GDAL的python环境&#xff08;如果大家需要&#xff0c;我可以后面出一片文章 问题一&#xff1a;QGIS连接到PostGIS数据库失败 错误描述&#xff1a; Connection to server at &quo…

211初试自命题复试线仅302分!延边大学计算机考研考情分析!

延边大学&#xff08;Yanbian University&#xff09;&#xff0c;简称“延大”&#xff0c;地处吉林省延边朝鲜族自治州&#xff0c;是国家“双一流”建设高校、国家“211工程”重点建设大学、西部开发重点建设院校、吉林省人民政府和教育部共同重点支持建设大学、吉林省人民政…

[保姆式教程]使用目标检测模型YOLO V5 OBB进行旋转目标的检测:训练自己的数据集(基于卫星和无人机的农业大棚数据集)

最近需要做基于卫星和无人机的农业大棚的旋转目标检测&#xff0c;基于YOLO V5 OBB的原因是因为尝试的第一个模型就是YOLO V5&#xff0c;后面会基于其他YOLO系列模型做农业大棚的旋转目标检测&#xff0c;尤其是YOLO V9&#xff0c;YOLO V9目前还不能进行旋转目标的检测&#…

C++ 实现AVL树

目录​​​​​​​ 0.二叉搜索树 1.AVL树的概念 2.AVL树节点的定义 3.AVL树的插入 4.AVL树的旋转逻辑 5.判断是否符合AVL树 6.完整代码 7.数据测试 0.二叉搜索树 C 搜索二叉树-CSDN博客 1.AVL树的概念 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近…

基于地理坐标的高阶几何编辑工具算法(2)——相交面裁剪

文章目录 工具步骤应用场景算法输入算法输出算法示意图算法原理后处理 工具步骤 选中一个需要裁剪的面&#xff0c;点击“相交面裁剪”工具&#xff0c;多选裁剪模板面&#xff0c;空格执行。 应用场景 常用于基于遥感影像的建筑物几何面编辑。 算法输入 一个待裁剪的面&a…

国家自然博物馆“云端自然”线上虚拟展厅是如何搭建的?

国家级综合性自然博物馆国家自然博物馆&#xff0c;联手积木易搭打造“云端自然”线上虚拟展览&#xff0c;形成一个集参观游览、科普教育为一体的线上虚拟数字博物馆平台&#xff0c;让数千以至数万年的古生物&#xff0c;栩栩如生地呈现在我们面前。 通过数字化的展示手段&am…

C# 文件清理

/// <summary>/// 定期清除文件/// </summary>/// <param name"fileDirect">文件夹</param>/// <param name"postFix">文件后缀</param>/// <param name"saveDay">保存天数</param>private voi…

blender 烘焙渲染图片,已经导出fbx,导出贴图。插件生成图片

1.新建一个模型。选择资产浏览器的材质&#xff0c;并拖动到模型身上&#xff0c;如下图。资产浏览器的材质可以网上找。 2.打开着色器面板。正下方着色器窗口中&#xff0c;点击空白取消选择&#xff0c;然后右击-添加-着色器-原理化BSDF&#xff0c;右击-添加-纹理-图像纹理。…

oracle怎么处理json格式

向数据库导入json相关jar包 loadjava -r -f -u bsuser/XXXX192.168.10.31/bsorcl json.jar 要删除的话&#xff0c;删除指定jar dropjava -u bsuser/XXXX192.168.10.31/bsorcl json.jar select * from user_java_classes 然后我们就可以取到json串中任意节点的值

几个原则

&#xff08;1&#xff09; 成功是成功之母&#xff0c;失败不是成功之母。100分的试卷一模一样&#xff0c;不及格的试卷千奇百怪。向成功者学习。 不要研究失败&#xff0c;因为研究了一万个失败的原因&#xff0c;也不能找到一把成功的钥匙。 &#xff08;2&#xff09; 要定…

Controlnet作者放出新的大招 IC-Light,可以操控图像生成时的光照,对内容主体重新打光生成符合新背景环境光照的图片

IC-Light代表Impose Constant Light,是一个控制图像照明的项目。可以操控图像生成时的光照&#xff0c;对内容主体重新打光生成符合新背景环境光照的图片。这下商品图合成这种需要最大程度保持原有主体 ID 需求的最大的问题解决了。 目前&#xff0c;已经发布了两种类型的模型…

如何将手机中的音乐转移到 SD 卡上?轻松传输音乐

概括 如何将音乐从手机转移到 SD 卡&#xff1f;我们的智能手机可以充当个人点唱机&#xff0c;因此有效管理我们的音乐库变得至关重要。无论您是存储空间不足还是只是想整理您的音乐收藏&#xff0c;将音乐从手机传输到 SD 卡都是一个实用的解决方案。 在本指南中&#xff0…

Python数据可视化(七)

绘制 3D 图形 到目前为止&#xff0c;我们一直在讨论有关 2D 图形的绘制方法和绘制技术。3D 图形也是数据可视化的 一个很重要的应用方面&#xff0c;我们接下来就重点讲解有关 3D 图形的实现方法。绘制 3D 图形通常需要导 入 mpl_toolkits 包中的 mplot3d 包的相关模块&#x…