【MySQL系列 05】Schema 与数据类型优化

良好的数据库 schema 设计和合理的数据类型选择是 SQL 获得高性能的基石。

一、选择优化的数据类型

MySQL 支持的数据类型非常多,选择正确的数据类型对于获得高性能至关重要。不管存储哪种类型的数据,下面几个简单的原则都有助于做出更好的选择。

1. 更小的通常更好

一般情况下,应该尽量使用可以正确存储数据的最小数据类型。例如只需要存储数值 0 ~ 200,tinyint unsigned 更好。更小的数据类型通常更快,因为它们占用更少的磁盘、内存和 CPU 缓存,并且处理时需要的 CPU 周期也更少。

2. 简单就好

简单数据类型的操作通常需要更少的 CPU 周期。例如,整型比字符操作代价更低,因为字符集和校对规则(排序规则)使字符比较比整型比较更复杂。这里有两个例子:一个是应该使用 MySQL 内建的类型而不是字符串来存储日期和时间,另外一个是应该用整型存储 IP 地址。

3. 尽量避免 NULL

很多表都包含可为 NULL(空值)的列,即使应用程序并不需要保存 NULL 也是如此,这是因为可为 NULL 是列的默认属性。即如果定义表结构时没有指定列为 NOT NULL,默认都是允许为 NULL 的。通常情况下最好指定列为 NOT NULL,除非真的需要存储 NULL 值

如果查询中包含可为 NULL 的列,对 MySQL 来说更难优化,因为可为 NULL 的列使得索引、索引统计和值比较逗更复杂。可为 NULL 的列会使用更多的存储空间,在 MySQL 里也需要特殊处理。当可为 NULL 的列被索引时,每个索引记录需要一个额外的字节,在 MyISAM 里甚至还可能导致固定大小的索引变成可变大小的索引。

通常把可为 NULL 的列改为 NOT NULL 带来的性能提升比较小,所以调优时没有必要首先在现有 schema 中查找并修改掉这种情况,除非确定这会导致问题。但是,如果计划在列上建索引,就应该尽量避免设计成可为 NULL 的列。

当然也有例外,例如,InnoDB 使用单独的位(bit)存储 NULL 值,所以对于稀疏数据(即很多值为 NULL,只有少数行的列有非 NULL 值)有很好的空间效率。但这一点不适用于 MyISAM。

那么,如何为列选择合适的数据类型呢?分两步:

  1. 首先确定合适的大类型:数字、字符串、时间等。这通常是很简单的。
  2. 选择具体类型。很多 MySQL 的数据类型可以存储相同类型的数据,只是存储的长度和范围不一样、允许的精度不同,或者需要的物理空间(磁盘和内存空间)不同。相同大类型的不同子类型数据有时也有一些特殊的行为和属性。

我们只讨论基本的数据类型。MySQL 为了兼容性支持很多别名,例如 INTEGER、BOOL,以及 NUMERIC。他们都只是别名。这些别名可能令人不解,但不会影响性能。如果建表时采用数据类型的别名,然后用 SHOW CREATE TABLE 检查,会发现 MySQL 报告的是基本类型,而不是别名。

1.1 整数类型

有两种类型的数字:整数(whole number)和实数(real number)。如果存储整数,可以使用这几种整数类型:TINYINTSMALLINTMEDIUMINTINT,BIGINT。分别使用 8,16,32,64位存储空间。他们可以存储的值范围从 -2^{(N-1)} 到 2^{(N-1)}-1,其中 N 是存储空间的位数。

整数类型有可选的 UNSIGNED 属性,表示不允许负值,这大致可以使正数的上限提高一倍。例如,TINYINT UNSIGNED 可以存储的范围是 0~255,而 TINYINT 的存储范围是 -128~127。

有符号和无符号类型使用相同的存储空间,并具有相同的性能,因此可以根据实际情况选择合适的类型。

MySQL 可以为整数类型指定宽度,例如 INT(11),对大多数应用这是没意义的:它不会限制值的合法范围,只是规定了 MySQL 的一些交互工具(例如 MySQL 命令行客户端)用来显示字符的个数。对于存储和计算来说,INT(1) 和 INT(20) 是相同的

:你选择的整数类型决定 MySQL 是怎么在内存和磁盘中保存数据的。然而,整数计算一般使用 64 位的 BIGINT 整数,即使在 32 位环境也是如此。(一些聚合函数除外,他们使用 DECIMAL 或 DOUBLE 进行计算)。

1.2 实数类型

实数是带有小数部分的数字。他们不只是为了存储小数部分,也可以使用 DECIMAL 存储比 BIGINT 还大的整数。MySQL 既支持精确类型,也支持不精确类型。

FLOATDOUBLE 类型支持使用标准的浮点运算进行近似计算

DECIMAL 类型用于存储精确的小数,在 MySQL 5.0 和更高版本,DECIMAL 类型支持精确计算。对于 DECIMAL 列,可以指定小数点前后所允许的最大位数。这会影响列的空间消耗。例如,DECIMAL(18,9) 小数点两边将各存储 9 个数字,一共使用 9 个字节:小数点前的数字用 4 个字节,小数点后的数字用 4 个字节,小数点本身占 1 个字节。MySQL 5.0 和更高版本中的 DECIMAL 类型允许最多 65 个数字

浮点类型在存储同样范围的值时,通常比 DECIMAL 使用更少的空间FLOAT 使用 4 个字节存储DOUBLE 占用 8 个字节

因为需要额外的空间和计算开销,所以应该尽量只在对小数进行精确计算时才使用 DECIMAL,例如存储财务数据等。

1.3 字符串类型

MySQL 支持多种字符串类型,每种类型还有很多变种。

1.3.1 VARCHAR 和 CHAR 类型

VARCHAR 和 CHAR 是两种最主要的字符串类型。

VARCHAR

VARCHAR 类型用于存储可变长字符串,是最常见的字符串数据类型。

需要使用 1 或 2 个额外字节记录字符串的长度,如果列的最大长度小于或等于 255 字节,则只使用 1 个字节表示,否则使用 2 个字节。

它比定长类型更节省空间,因为它仅使用必要的空间(例如,越短的字符串使用越少的空间),所以对性能也有帮助。

  

但由于 VARCHAR 行是变长的,在 UPDATE 时可能使行变得比原来更长,这就导致需要做额外的工作。

以下情况使用 VARCHAR 是合适的:

  1. 字符串列的最大长度比平均长度大很多;
  2. 列的更新很少,所以碎片不是问题;
  3. 使用了像 UTF-8 这样复杂的字符集,每个字符都使用不同的字节数进行存储。

CHAR

CHAR 类型是定长的,MySQL 总是根据定义的字符串长度分配足够的空间。

CHAR 适合存储很短的字符串,或者所有值都接近同一个长度。

以下情况使用 CHAR 是合适的:

  1. CHAR 非常适合存储密码的 MD5 值,因为这是一个定长的值。
  2. 对于经常变更的数据,CHAR 也比 VARCHAR 更好,因为定长的 CHAR 类型不容易产生碎片。
  3. 对于非常短的列,CHAR 比 VARCHAR 在存储空间上也更有效率。例如,用 CHAR(1) 来存储只有 Y 和 N 的值,如果采用单字节字符集只需要一个字节,但是 VARCHAR(1) 却需要两个字节,因为还有一个记录长度的额外字节。

1.3.2 BLOB 和 TEXT 类型

BLOB 和 TEXT 都是为存储很大的数据而设计的字符串数据类型,分别采用二进制和字符方式存储。

BLOB 和 TEXT 之间仅有的不同是 BLOB 类型存储的是二进制数据,没有排序规则或字符集,而 TEXT 类型有字符集和排序规则。

MySQL对 BLOB 和 TEXT 列进行排序与其他类型是不同的:它只对每个列的最前 max_sort_length 字节而不是整个字符串排序。

尽量避免使用 BLOB 和 TEXT 类型。

1.4 日期和时间类型

MySQL 可以使用许多类型来保存日期和时间值,例如 YEAR 和 DATE等。其中 DATETIME 和 TIMESTAMP 是 MySQL 提供的两种比较相似的保存时间的数据类型,可以精确到秒。他们两者究竟如何选择呢?

下面我们来简单对比一下二者。

1.4.1 时区信息

DATETIME 类型是没有时区信息的(时区无关)。DATETIME 类型保存的时间都是当前会话所设置的时区对应的时间。

TIMESTAMP 和时区有关。TIMESTAMP 类型字段的值会随着服务器时区的变化而变化,自动换算成相应的时间,说简单点就是在不同时区,查询到同一条记录此字段的值会不一样。

下面实际演示一下!

建表 SQL 语句:

CREATE TABLE `time_zone_test` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`date_time` datetime DEFAULT NULL,`time_stamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

插入数据:

INSERT INTO time_zone_test(date_time,time_stamp) VALUES(NOW(),NOW());

查看数据:

select date_time,time_stamp from time_zone_test;

结果:

+---------------------+---------------------+
| date_time           | time_stamp          |
+---------------------+---------------------+
| 2020-01-11 09:53:32 | 2020-01-11 09:53:32 |
+---------------------+---------------------+

我们修改当前会话的时区:

set time_zone='+8:00';

再次查看数据;

+---------------------+---------------------+
| date_time           | time_stamp          |
+---------------------+---------------------+
| 2020-01-11 09:53:32 | 2020-01-11 17:53:32 |
+---------------------+---------------------+

1.4.2 占用空间

下图是 MySQL 日期类型所占的存储空间:

在 MySQL 5.6.4 之前,DATETIME 和TIMESTAMP 的存储空间是固定的,分别是 8 字节和 4 字节。但是从 MySQL 5.6.4 开始,他们的存储空间会根据毫秒精度的不同而变化,DATETIME 的范围是 5~8 字节,TIMESTAMP 的范围是 4~7 字节。

1.4.3 表示范围

TIMESTAMP 表示的时间范围更小,只能到 2038 年

  • DATETIME:1000-01-01 00:00:00.000000 ~ 9999-12-31 23:59:59.499999
  • TIMESTAMP:1970-01-01 00:00:01.000000 ~ 2038-01-19 03:14:07.499999

1.4.4 数值时间戳是更好的选择吗?

很多时候,我们也会使用 INT 或者 BIGINT 类型的数值也就是数值时间戳来表示时间。

这种存储方式具有 TIMESTAMP 类型所具有的一些有点,并且使用它进行日期排序以及对比等操作的效率会更高,跨系统也很方便。缺点也很明显,就是数据的可读性太差了,无法直观的看到具体时间。

MySQL 中时间到底怎么存储才好?DATETIME?TIMESTAMP?还是数值时间戳?

并没有一个银弹,很多程序员会觉得数值型时间戳是真的好,效率又高还各种兼容,但是很多人有觉得它表现的不够直观。

除了特殊行为之外,通常也应该尽量使用 TIMESTAMP,因为它比 DATETIME 空间效率更高。但每种方式都有各自的优势,根据实际场景选择最合适的才是王道。

下面再对这三种方式做一个简单的对比,以供大家在实际开发中选择合适的存储时间的类型:

1.5 位数据类型

MySQL 有少数几种存储类型使用紧凑的位存储数据。所有这些位类型,不管底层存储格式和处理方式如何,从技术上来说都是字符串类型。

BIT

BIT 列的最大长度是 64 位,MySQL 把 BIT 当作字符串类型,而不是数字类型。当检索 BIT(1) 的值时,结果是一个包含二进制 0 或 1 值的字符串,而不是 ASCII 码的 “0” 或 “1”。然而,在数字上下文的场景中检索时,结果将是位字符串转换成的数字。如果需要和另外的值比较结果,一定要记得这一点。例如,如果存储一个值 b '00111001'(二进制值等于 57)到 BIT(8) 的列并且检索它,得到的内容是字符码为 57 的字符串。也就是说得到 ASCII 码为 57 的字符 “9”。但是在数字上下文场景中,得到的是数字 57:

这是相当令人费解的,所以我们应该谨慎使用 BIT 类型,对于大部分应用,最好避免使用这种类型

SET

如果需要保存很多 true/false 值,可以考虑合并这些列到一个 SET 数据类型,它在 MySQL 内部是以一系列打包的位的集合来表示的。这样就有效地利用了存储空间,并且 MySQL 有像 FIND_IN_SET() 和 FIELD() 这样的函数,方便地在查询中使用。它的主要缺点是改变列的定义的代价较高:需要 ALTER TABLE,这对大表来说是非常昂贵的操作。一般来说,也无法在 SET 列上通过索引查找。

1.6 选择标识符(identifier)

为标识列(identifier column)选择合适的数据类型非常重要,一般来说更有可能用标识列与其他值进行比较(例如,在关联操作中),或者通过标识列寻找其他列。

整数通常是标识列最好的选择,因为他们很快并且可以使用 AUTO_INCREMENT。千万不要使用 ENUM 和 SET 类型作为标识列;应尽量避免使用字符串作为标识列,因为它们很消耗空间,并且通常比数字类型慢。

1.7 特殊类型数据

某些类型的数据并不直接与内置类型一致。低于秒级精度的时间戳就是一个例子。

另外一个例子是一个 IPv4 地址。人们经常使用 VARCHAR(15) 的列来存储 IP 地址。然而,它们实际上是 32 位无符号整数,不是字符串。用小数点将地址分成四段的表示方法只是为了让人们阅读容易。所以应该用无符号整数存储 IP 地址。MySQL 提供 INET_ATON()INET_NTOA() 函数在这两种表示方法之间转换。

二、schema 设计中的陷阱

2.1 太多的列

MySQL 的存储引擎 API 工作时需要在服务器层和存储引擎层之间通过行缓冲格式拷贝数据,然后在服务器层将缓冲内容解码成各个列。从行缓冲中将编码过的列转换成行数据结构的操作代价是非常高的。

  

如果计划使用数千个字段,必须意识到服务器的性能特征会有一些不同,即查询会变得很慢。

2.2 太多的关联

MySQL 限制了每个关联操作最多只能有 61 张表。经验法则,希望查询执行得快速且并发性好,单个查询最好在 12 个表以内做关联。

2.3 全能的枚举

注意防止过度使用枚举(ENUM)。CREATE TABLE ..(country enum('','1','2','3',...,'31')) 这种模式的 schema 设计非常糟糕。当需要再枚举列表中增加一个新的国家时就要做一次 ALTER TABLE 操作。在 MySQL 5.0 以及更早的版本中 ALTER TABLE 是一种阻塞操作。

2.4 变相的枚举

枚举(ENUM)列允许在列中存储一组定义值中的单个值,集合(SET)列则允许在列中存储一组定义值中的一个或多个值。例子:CREATE TABLE ...(is_default set('Y','N') NOT NULL default 'N'),如果这里真和假两种情况不会同时出现,那么毫无疑问应该使用枚举列代替集合列。

2.5 NULL 的替换方案

前面说了尽量不使用 NULL,我们可以使用 -1,0,''空字符串来代替。但是不要每个地方都这样用,有时候使用替代方案可能会导致编写代码和业务场景变得更加复杂,比如其他部门都用 NULL,我们使用 -1,这样很多调用部分都得做出相应的修改。
在具体的场景可以具体分析,并不是说 NULL 就不能用了。

三、范式和反范式

对于任何给定的数据通常都有很多种表示方法,从完全的范式化到完全的反范式化,以及两者的这种。在范式化的数据库中,每个事实数据会出现并且只出现一次。相反,在反范式化的数据库中,信息是冗余的,可能会存储在多个地方。

3.1 范式的优点和缺点

当为性能问题而寻求帮助时,经常会被建议对 schema 进行范式化设计,尤其是写密集的场景。这通常是个好建议。因为范式化通常能够带来以下好处:

  • 范式化的更新操作通常比反范式化要快。
  • 当数据较好的范式化时,就只有很少或者没有重复数据,所以只需要修改更少的数据。
  • 范式化的表通常更小,可以更好的放在内存里,所以执行操作会更快。
  • 很少有多余的数据意味着检索列表数据时更少需要 DISTINCT 或者 GROUP BY 语句。

  

范式化设计的 schema 的缺点是通常需要关联。这不但代价昂贵,也可能使一些索引策略无效。

3.2 反范式的优点和缺点

反范式化设计的优点有:

  • 反范式化的 schema 因为所有数据都在一张表中,可以很好的避免关联。可以有效避免随机I/O。
  • 单独的表也能使用更有效的索引策略。

  

反范式化的缺点是数据存储冗余,修改数据时可能发生不一致。

3.3 混用范式化和反范式化

范式化和反范式化的 schema 各有优劣,怎么选择最佳的设计?

事实上,完全的范式化和完全的反范式化 schema 都是实验室里才有的东西:在真实世界中很少会这么极端地使用。

   

在实际应用中经常需要混用,可能使用部分范式化的 schema、缓存表,以及其他技巧。

四、小结

良好的 schema 设计原则是普遍适用的,但 MySQL 有它自己的实现细节要注意。概括来说,尽可能保持任何东西小而简单总是好的。MySQL 喜欢简单,需要使用数据库的人应该也同样会喜欢简单的原则:

  • 尽量避免多度设计,例如会导致极其复杂查询的 schema 设计,或者有很多列的表设计(很多的意思是介于有点多和非常多之间)。
  • 使用小而简单的合适数据类型,除非真实数据模型中有确切的需要,否则应该尽可能地避免使用 NULL 值。
  • 尽量使用相同的数据类型存储相似或相关的值,尤其是要在关联条件中使用的列。
  • 注意可变长字符串,其在临时表和排序时可能导致悲观的按最大长度分配内存。
  • 尽量使用整型定义标识列。
  • 避免使用 MySQL 已经遗弃的特性,例如指定浮点数的精度,或者整数的显示宽度。
  • 小心使用 ENUM 和 SET。虽然它们用起来很方便,但是不要滥用,否则有时候会变成陷阱。最好避免使用 BIT。
  • 范式是好的,但是反范式(大多数情况下意味着重复数据)有时也是必须的,并且能带来好处。

参考:

MySQL 官方文档:https://dev.mysql.com/doc/refman/8.0/en/storage-requirements.html

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据通信练习题

1.0osi七层模型 应用层 data 表示层 会话层 传输层 数据段 防火墙,端口(TCP UDP) 网络层 数据包 路由器 数据链路层 数据帧 交换机 物理层 比特流 网卡 2.IP地址分类 私有地址 A类 0--127 10.0.0.0…

提升日志管理效率:掌握CKA认证中的边车容器技巧

往期精彩文章 : 提升CKA考试胜算:一文带你全面了解RBAC权限控制!揭秘高效运维:如何用kubectl top命令实时监控K8s资源使用情况?CKA认证必备:掌握k8s网络策略的关键要点提高CKA认证成功率,CKA真题中的节点维…

C++字符串操作【超详细】

零.前言 本文将重点围绕C的字符串来展开描述。 其中,对于C/C中字符串的一些区别也做出了回答,并对于C的(string库)进行了讲解,最后我们给出字符串的不同表达形式。 开发环境: VS2022 一.字符串常量跟字…

光伏数字化管理平台:驱动绿色能源革命的智能化引擎

随着全球对可再生能源需求的不断增长,光伏产业已经成为推动绿色能源革命的重要力量。在这个背景下,光伏数字化管理平台应运而生,以其强大的数据处理、实时监控和智能优化功能,为光伏电站的运营管理和维护带来了革命性的变革。 光伏…

如何正确选择国外服务器的带宽和线路呢?

国外大带宽服务器是一种提供高带宽、高速网络连接和良好稳定性的服务器,但在中国使用这类服务器可能涉及到违反法律法规的风险。因此我无法为你提供相关帮助。接下来和源库一起了解如何正确选择国外服务器的带宽和线路呢? 考虑目标用户的地理位置。如果目标用户主要…

SpringBoot注解--08--注解@JsonInclude

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 JsonInclude注解是jackSon中最常用的注解之一,是为实体类在接口序列化返回值时增加规则的注解 1.JsonInclude用法2.JsonInclude注解中的规则有 案例需求…

WordPress供求插件API文档:用户登录

该文档为WordPress供求插件文档,详情请查看 WordPress供求插件:一款专注于同城生活信息发布的插件-CSDN博客文章浏览阅读67次。WordPress供求插件:sliver-urban-life 是一款专注于提供同城生活信息发布与查看的插件,该插件可以实…

PyCM:Python中的混淆矩阵库

PyCM:Python中的混淆矩阵库 在机器学习和数据科学领域,评估模型的性能是至关重要的。混淆矩阵是一种常用的评估工具,用于可视化和量化分类模型的预测结果。PyCM是一个开源的Python库,提供了丰富的功能来计算和分析混淆矩阵。本文将…

2024 PhpStorm激活,分享几个PhpStorm激活的方案

文章目录 PhpStorm 公司简介我这边使用PhpStorm的理由PhpStorm 2023.3 最新变化AI Assistant 预览阶段结束 正式版基于 LLM 的代码补全测试代码生成编辑器内代码生成控制台中基于 AI 的错误解释 Pest 更新PHP 8.3 支持#[\Override] 特性新的 json_validate() 函数类型化类常量弃…

HubSpot和NETFARMER是什么关系?

HubSpot和NETFARMER之间的关系是合作伙伴关系,特别是在亚太地区。NETFARMER作为HubSpot的合作伙伴,专注于帮助企业在海外市场获得更多客户,实现业务增长和成功。 NETFARMER具备丰富的经验和专业的营销团队,他们深入了解亚太地区各…

软件测试APP完整测试作业流程(附流程图),公司级软件测试流程化办公

目录 1. 概述 2. 软件测试流程 3. 软件测试周期人员活动图 4. 总结 1. 概述 1.1 目的 有效的保证软件质量; 有效的制定不同测试类型(软件系统测试、音频主观性测试、Field Trial、专项测试、自动化测试、性 能测试、用户体验测试)的软件…

mysql 常用命令

1、显示锁的时间 show status like innodb_row_lock%;2、锁一行的方法 //开启 begin; //锁一行 select * from tbl_user where name 1aa1 for update;//解锁 commit;3、设置不自动提交 set autocommit 0; //自动提交 set autocommit 1;4、查看是否支持profile show vari…

go go.mod file not found in current directory or any parent directory

场景: 安装好 liteide 之后创建了第一个 “hello world” 的golang 项目,却报了如下错误。 原因分析: go 的环境配置问题。与 golang 的包管理有关。 解决方案: 如果你是 Windows 系统,快捷键 “WinR”&#xff0c…

使用Docker实现Jenkins+Python + Pytest +Allure 接口自动化

一、Jenkins搭建 参考《Docker 安装 Jenkins》 进入 jenkins 容器 CLI 界面 docker exec -itu root jenkins /bin/bash二、准备条件 1、替换镜像内源 为了安装wget,默认用yum会安装不上wget命令,参考文章《docker容器内如何更换yum源【只想换成国内…

EE5437-IOT(Lecture 07-Control Interface System)

Review: introduce the micro input device system(MIDS) • The calibration and testing has been covered • The introduction to filters with the example called Butterworth filter and the maths have been also demonstrated. …

vxe-table配合Export2Excel导出object类型数据{type,count}。表格数据呈现是利用插槽,导出只要count该怎么做

先贴一张数据来: 一、然后是vxe-grid的columns配置: 然后就正常用封装好的Export2Excel就行。 碰到一次在控制台报错: 没复现出来,大概就说是count咋样咋样。 以后碰到的话再说,各位要用的话也注意看看 二、或者 用js…

Unity笔记:C#基础(1)

杂项 虚函数 CSDN - C虚函数详解 cnblog - C#中的虚函数virtual 常量池与new 在C#中,string是不可变的,这意味着对string对象的操作通常会返回一个新的string对象,而不会修改原始的string对象。因此,几乎所有涉及更改string内…

redis最新版本在Windows系统上的安装

一、说明 这次安装操作主要是根据redis官网说明,一步步安装下来的,英语比较好的同学,可以直接看文章底部的超链接1,跳到官网按步操作即可。 目前redis的最新稳定版本为redis7.2。 二、Windows环境改造 Redis在Windows上不被官方…

学校里的软件测试专业技能到底怎样,为什么应届生都很难找工作?

大家好,今天和以为在学校教软件测试的老师聊了天,主要聊的主题是-为什么现在大专生就业这么困难。主要总结以下几点! 一是受当下大环境的影响(比如疫情、俄乌、单边主义等);二是今年的应届生实在太多&…

智慧城市的前景:数字孪生技术在智慧城市中的应用前景

目录 一、引言 二、数字孪生技术及其在智慧城市中的应用概述 三、数字孪生技术在智慧城市中的应用前景 1、城市规划与仿真模拟 2、智能交通与出行服务 3、智慧环保与可持续发展 4、智慧公共服务与社会治理 5、智慧能源与绿色建筑 四、数字孪生技术在智慧城市中的挑战与…