【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.mzph.cn/news/737803.shtml

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

相关文章

C语言学习-day19-函数2

自定义函数:自己定义的函数 以strcpy为例子: 自定义函数一样,需要函数名,返回值类型,函数参数。 函数的组成: ret_type fun_name(para1, *) { statement;//语句项 } ret_type 返回类型 fun_name 函数…

weiphp5.0存在远程代码执行漏洞

@[toc] 免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该文章仅供学习用途使用。 1. weiphp5.0简介 微信公众号搜索:南风漏洞复…

c++ 开发环境 LNK1104: 无法打开文件“carve.lib” 已解决

别人分享, 和自己最近遇到问题一摸一样。以为没什么用的静态资源,结果 无法编译。 昨天安装配置了,结果今天早上打开电脑,所以dll的工程全部报错: 1>------ 已启动全部重新生成: 项目: Dll_test, 配置: Debug x64…

pycharm中连接远程服务器

文章目录 概要文件进行映射将本地的project和远程的project进行映射,一定要使用sftp本地文件和远程的位置配置不想将远程的文件同步时候,可以进行下面设置 配置远程服务器的python解释器需要setting-->python interpreter-->add---> on ssh选择…

《Vue3 基础知识》事件总线 bus(与Vue2 有差异,使用 mitt 库)

前言 Vue2 与 Vue3 事件总线区别 Vue2 使用 $on,$off 和 $once 实例方法,创建一个事件总线,可在整个应用中做全局事件监听;Vue3 移除 $on,$off 和 $once 实例方法 ,但提供了解决方案,使用库 m…

crossover玩不了qq游戏大厅怎么办 仍有五亿人坚持用QQ crossover玩游戏 Mac电脑玩QQ游戏

从1999年2月,QQ首个版本QICQ(OPEN-ICQ)上线。到2024年,靠着5亿月活用户,守住社交领域TOP2位置。你还记得QQ经典的铃声吗? 根据月狐数据2023年12月的统计,QQ月活跃账户数比微博和知乎加在一起还要…

分享10个ai人工智能ppt生成软件,一键轻松搞定PPT制作!

ai 人工智能发展至今,已经诞生了各式各样的 AI 软件,最常见的如 AI 写作软件、AI 绘画软件、AI 人工智能 ppt 生成器、AI 人工智能抠图软件等等。对每天要面对各类文档、演示文稿(PPT)的职场人来说,最被需要的 AI 软件…

颜色检测python项目

注意:本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 ([www.aideeplearning.cn]) 什么是颜色检测? 颜色检测是检测任何颜色名称的过程。很简单不是吗?嗯,对于人类来说,这是一项极…

教你怎么写苹果群控系统!

在数字化时代,随着智能手机的普及和iOS系统的广泛应用,苹果设备的管理和控制变得日益重要,为了满足这一需求,苹果群控系统应运而生。 一、系统概述 苹果群控系统是一种能够对多台苹果设备进行集中管理和控制的软件系统。通过该系…

2024年会声会影 迎接来了七大新功能

我喜欢Corel VideoStudio 会声会影2024旗舰版,因为它使用起来很有趣。它很容易使用,但仍然给你很多功能和力量。VideoStudio让我与世界分享我的想法!“这个产品的功能非常多,我几乎没有触及它的表面,我可以做大量的编辑…

【Linux】权限管理(文件的访问者、类型和访问权限,chmod、chown、chgrp、umask,粘滞位)

目录 00.前言 01.文件访问者的分类 02.文件类型和访问权限 文件类型: 文件基本权限: 03.文件权限值的表示方法 04.访问权限的设置 (1)chmod (2)chown (3)chgrp &#xff0…

Linux:kubernetes(k8s)Deployment的操作(12)

创建deployment 命令 kubectl create deploy nginx-deploy --imagenginx:1.7.9 再去使用以下命令分别查询 ubectl get deploy kubectl get replicaset kubectl get pod 他是一个层层嵌套的一个关系 首先是创建了一个 deploy 里面包含着replicaset replicaset里面含有…

mysql中 COALESCE和CASE WHEN的使用以及创建或替换视图

create or replace view 自理能力评估视图 as SELECT ehr_zlnlpg.ID AS ID, ehr_zlnlpg.GRID AS GRID, ehr_zlnlpg.TJID AS TJID, ehr_grjbxx.Name AS 姓名, ehr_grjbxx.Sex AS 性别, ehr_grjbxx.Cardnum AS 身份证号, ehr_zlnlpg.SCORESUM AS 总…

代码随想录 贪心算法-中等题目-序列问题

376.摆动序列 376. 摆动序列 中等 如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。 例如, [1, 7…

ELEVENLABS AI在线AI语音合成工具,28种语言

一、Elevenlabs简介 ElevenLabs 可以使用合成语音、克隆语音或全新的「人工」语音将文本转化为语音,并且这些语音可以模仿不同性别、年龄和种族的声音。 ElevenLabs基于目前强大的生成式语音模型,提供文本生成语音、语音合成、语音克隆和语音识别分类功…

【好玩的游戏项目】在Linux系统下部署star-battle太空飞船射击小游戏

【好玩的开源项目】在Linux系统下部署 star-battle太空飞船射击小游戏 一、star-battle小游戏介绍1.1 star-battle小游戏简介1.2 star-battle小游戏玩法1.3 开源地址 二、本次实践介绍2.1 本地环境规划2.2 本次实践介绍2.3 Apache HTTP Server简介 三、安装httpd软件3.1 检查yu…

面试官:说说你对事件循环的理解

一、事件循环是什么 首先,JavaScript是一门单线程的语言,意味着同一时间内只能做一件事,但是这并不意味着单线程就是阻塞,而实现单线程非阻塞的方法就是事件循环 在JavaScript中,所有的任务都可以分为 同步任务&#…

如何保证消息不被重复消费?或者说,如何保证消息消费的幂等性?

一、面试官心理分析 其实这是很常见的一个问题,这俩问题基本可以连起来问。既然是消费消息,那肯定要考会不会重复消费?能不能避免重复消费?或者重复消费了也别造成系统异常可以吗?这个是 MQ领域的基本问题,…

还不知道快速原型设计?别担心,我们来解释给你听!

从一个想法到产品的实施是一个混乱的过程,毫无疑问,我们需要努力建立这个想法。但“光明”的想法是好是坏呢?幸运的是,我们有一个工具可以做到这一点——原型。原型是最终产品的模拟或样本版本,可用于发布前与用户反复…

部署私有KMS服务器,并设置自动激活Windows和office

介绍 vlmcsd是一个KMS激活服务器的模拟器,可以在Windows Server之外的平台上部署自己的KMS服务器。它是一个开源项目,由Wind4开发,目前在Linux上运行(包括Android、FreeBSD、Solaris、Minix、Mac OS、iOS和Windows等)…