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

news2024/11/16 3:28:16

良好的数据库 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.coloradmin.cn/o/1508830.html

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

相关文章

软件测试面试需要准备什么?面试有什么技巧?看完面试轻松解决

前言 无论是在校招还是社会企业招聘中,应聘者总是要经过层层的考核才能被聘用。然而,在招聘时,设置的编程以及非技术面试问题,真的有必要吗?如此就能考核出一位开发者的真实水平? 说到底就是考验你的技术以…

LuGre摩擦模型详解

文章目录 原理Matlab 实现原理

家用洗地机如何挑选?介绍几款不错的适用型号

面对繁重的家务清洁,洗地机悄然走进了我们的生活,它以智能的科技与卓越的性能,高效地清洁每一个角落,带来前所未有的居家体验。这不仅是一种清洁工具的革新,更是对舒适生活品质的不懈追求。接下来,就让我们…

蓝桥杯练习系统(算法训练)ALGO-977 P0805大数乘法

资源限制 内存限制:256.0MB C/C时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s 当两个比较大的整数相乘时,可能会出现数据溢出的情形。为避免溢出,可以采用字符串的方法来实现两个大数之间的…

计算机网络-第5章 运输层(1)

主要内容:进程之间的通信与端口、UDP协议、TCP协议、可靠传输原理(停止等待协议、ARQ协议)、TCP报文首部、TCP三大题:滑动窗口、流量控制、拥塞控制机制 5.1 运输层协议概述 运输层向它上面的应用层提供通信服务,真正…

SpringCloud(21)之SpringCloud Alibaba Nacos实战应用

一、Nacos安装 1.1 Nacos概述 Nacos是Alibaba微服务生态组件中的重要组件之一,主要用它实现应用的动态服务发现、配置管理、 服务管理。Nacos discovery alibaba/spring-cloud-alibaba Wiki GitHub Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简…

鸿蒙开发(四)-低代码开发

鸿蒙开发(四)-低代码开发 本文主要介绍下鸿蒙下的低代码开发。 鸿蒙低代码是指在鸿蒙操作系统进行应用开发时,采用简化开发流程和减少编码量的方式来提高开发效率。 1:开启低代码开发 首先我们打开DevEco Studio .然后创建工程。 如图所示&#xff…

设计模式:软件开发的秘密武器

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

升级ChatGPT4.0失败的解决方案

ChatGPT 4.0科普 ChatGPT 4.0是一款具有多项出众功能的新一代AI语言模型。以下是关于ChatGPT 4.0的一些关键特点和科普内容: 多模态:ChatGPT 4.0具备处理不同类型输入和输出的能力。这意味着它不仅可以接收文字信息,还能处理图片、视频等多…

RESTful API学习

RESTful API REST(英文:Representational State Transfer,简称REST,直译过来表现层状态转换)是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和…

手把手教使用静默 搭建Oracle 19c 一主一备ADG集群

一、环境搭建 主机IPora19192.168.134.239ora19std192.168.134.240 1.配置yum源 1.配置网络yum源 1.删除redhat7.0系统自带的yum软件包; rpm -qa|grep yum >oldyum.pkg 备份原信息rpm -qa|grep yum|xargs rpm -e --nodeps 不检查依赖,直接删除…

让Putty支持Tab页(多连接管理)

让Putty支持Tab页(多连接管理) 1 介绍2 PuTTY缺陷3 支持Tab页4 支持用户名和密码保存 1 介绍 PuTTY是一个Telnet、SSH、rlogin、纯TCP以及串行接口连接软件。PuTTY为一开放源代码软件,主要由Simon Tatham维护,使用MIT licence授权…

定制红酒:定制红酒的预算控制与价值体现

在云仓酒庄洒派,云仓酒庄洒派理解消费者对于定制红酒的预算控制和价值体现的关注。因此,云仓酒庄洒派致力于为消费者提供品质、性价比的定制红酒服务。 首先,云仓酒庄洒派明确定制红酒的预算范围。在了解消费者的预算要求后,云仓酒…

nginx禁止国外ip访问

1.安装geoip2扩展依赖 yum install libmaxminddb-devel -y 2.下载ngx_http_geoip2_module模块 https://github.com/leev/ngx_http_geoip2_module.git 3.编译安装 ./configure --add-module/datasdb/ngx_http_geoip2_module-3.4 4.下载最新数据库文件 模块安装成功后,还要…

Dockerfile的使用,怎样制作镜像

Docker 提供了一种更便捷的方式,叫作 Dockerfile docker build命令用于根据给定的Dockerfile构建Docker镜像。 docker build命令参数: --build-arg,设置构建时的变量 --no-cache,默认false。设置该选项,将不使用Build …

Docker学习——Dock镜像

什么是Docker镜像 Docker 镜像类似于虚拟机镜像,可以将它理解为一个只读的模板。 一个镜像可以包含一个基本的操作系统环境,里面仅安装了 Apache 应用程序(或 用户需要的其他软件) 可以把它称为一个 Apache 镜像。镜像是创建 Do…

Windows环境部署Hadoop-3.3.2和Spark3.3.2

目录 一、Windows环境部署Hadoop-3.3.2 1.CMD管理员解压Hadoop压缩包 2.配置系统环境变量 3.下载hadoop winutils文件 4.修改D:\server\hadoop-3.3.2\etc\hadoop目录下的配置文件 (1)core-site.xml (2)hdfs-site.xml (3)mapred-site.xml (4)yarn-site.xml (5)workers…

Extended Feature Pyramid Network for SmallObject Detection

摘要 各种尺度的特征耦合会削弱小对象的性能,本文中,我们提出了具有超高分辨率金字塔的扩展特征金字塔网络(EFPN ),专门用于小目标检测。具体来说,我们设计了一个新模块,称为特征纹理转移&#…

智能测径仪的精度主要依赖什么

关键字:智能测径仪镜头洁净度,智能测径仪系统自检,测径仪智能降温,智能测径仪远程升级,智能测径仪算法改进, 智能测径仪的精度保证主要依赖于以下几个方面: 智能监测镜头的洁净度:智…

二,几何相交---4,BO算法---(2)比较和排序

在某一时刻xt,扫描线从左到右时,一部分线段会与扫描线相交,此时此刻,线段可以分成高低顺序, 那么对于给定两条线段,是如何变化的呢?有两个端点,左端点和右端点, 三种情况…