前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >MySQL 8.0 OCP (1Z0-908) 考点精析-性能优化考点5:表连接算法(join algorithm)

MySQL 8.0 OCP (1Z0-908) 考点精析-性能优化考点5:表连接算法(join algorithm)

作者头像
SQLplusDB
发布于 2023-08-17 01:13:22
发布于 2023-08-17 01:13:22
54300
代码可运行
举报
运行总次数:0
代码可运行

MySQL表连接的算法

我们知道对于Oracle的表连接,根据SQL连接条件主要支持如下三种连接方法(算法):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- 嵌套循环连接(Nested Loops Joins)
- 哈希连接(Hash Joins)
- 排序合并连接(Sort Merge Joins)

对于MySQL而言,支持的连接算法主要包括如下两种:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- 嵌套循环连接(Nested Loops Joins)
- 哈希连接(Hash Joins)

对于嵌套循环连接(Nested Loops Joins),又可以分为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- 简单嵌套循环连接(Simple  Nested-Loop Join Algorithm)
- 块嵌套循环连接(Block Nested-Loop Join Algorithm,BNL)
- 批量键值访问连接(Batched Key Access Joins,BKA

嵌套循环连接(Nested Loops Joins)

简单嵌套循环连接(Simple Nested-Loop Join Algorithm)

对于进行嵌套循环连接的两个表,可以分别称为外部表(驱动表)和内部表。

进行简单嵌套循环连接(Simple Nested-Loop Join Algorithm)时候,会读取外部表(驱动表)中的一条记录,然后根据连接条件扫描内部表,反复循环,直到遍历完驱动表所有满足谓词条件的记录。

例:对于如下t1、t2、t3三个表的连接来说,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Table   Join Type
t1      range
t2      ref
t3      ALL

简单嵌套循环连接算法的伪代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
for each row in t1 matching range {
  for each row in t2 matching reference key {
    for each row in t3 {
      if row satisfies join conditions, send to client
    }
  }
}
块嵌套循环连接(Block Nested-Loop Join Algorithm, BNL)

简单嵌套循环连接需要反复读取多次内部表(扫描内部表次数相当于驱动表中所有满足谓词条件的记录)。

块嵌套循环连接对这种连接算法进行了优化,在读取驱动表(外部表)时,一次性缓存多条驱动表的记录到 Join Buffer,然后拿Join Buffer中的记录批量与内层循环读取的记录进行匹配。BNL一般用于内连接。

通过块嵌套循环连接可以大大降低对内部表的扫描次数。

对于前面例中t1、t2、t3三个表的连接来说,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Table   Join Type
t1      range
t2      ref
t3      ALL

块嵌套循环连接算法的伪代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
for each row in t1 matching range {
  for each row in t2 matching reference key {
    store used columns from t1, t2 in join buffer
    if buffer is full {
      for each row in t3 {
        for each t1, t2 combination in join buffer {
          if row satisfies join conditions, send to client
        }
      }
      empty join buffer
    }
  }
}

if buffer is not empty {
  for each row in t3 {
    for each t1, t2 combination in join buffer {
      if row satisfies join conditions, send to client
    }
  }
}

参考: Block Nested-Loop Join Algorithm https://dev.mysql.com/doc/refman/8.0/en/nested-loop-joins.html

连接缓冲区(join buffer)及join_buffer_size参数

每个进程的连接缓冲区(join buffer)的大小由系统环境变量join_buffer_size控制。

Command-Line Format

–join-buffer-size=#

System Variable

join_buffer_size

Scope

Global, Session

Dynamic

Yes

SET_VAR Hint Applies

Yes

Type

Integer

Default Value

262144

Minimum Value

128

Maximum Value (Windows)

4294967168

Maximum Value (Other, 64-bit platforms)

18446744073709551488

Maximum Value (Other, 32-bit platforms)

4294967168

Unit

bytes

Block Size

128

join_buffer_size是用于控制普通索引扫描、范围索引扫描和不使用索引的连接(全表扫描)的缓冲区的最小大小。 MySQL 8.0.18及更高版本中,join_buffer_size变量还用于控制哈希连接使用的内存量。

使用块嵌套循环(BNL)时,较大的连接缓冲区意味着可以将驱动表(外部表)的所有行都存储在连接缓冲区中; 使用块嵌套循环(BNL)时,较大的连接缓冲区意味着对连接操作的右侧表进行的顺序访问就越多。 因此,增加join_buffer_size的大小在某些情况下可以显着提高性能。

但是,增加join_buffer_siz意味着增大进程的内存缓冲区大小,如果全局设置的比较大,可能导致内存分配时间时间长,进而导致性能大幅下降。所以建议全局设置保持较小,仅在执行大型连接的会话中将会话级别的值设置为较大值(或者使用/*+ SET_VAR(join_buffer_size= XX) */提示针对个别SQL设置较大值)。

参考: join_buffer_size https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_join_buffer_size

块嵌套循环连接(Block Nested-Loop Join Algorithm, BNL)扩展

随着MySQL数据库的演进,MySQL对块嵌套循环(BNL)连接算法进行了扩展,扩展后的块嵌套循环(BNL)连接算法,不仅可以用于内连接,还可以用于外连接、半连接和嵌套外连接。

  • 当使用连接缓冲区(join buffer)执行这些操作时,放入缓冲区的每一行都会被赋予一个匹配标志。
  • 外连接操作时,根据条件检查【要连接的表】的每一行是否与连接缓冲区中的每一行匹配。
  • 如果匹配,将形成一个新的扩展行(原始行加上【要连接的表】的列),并会对缓冲区中匹配行的匹配标志进行标记。
  • 检查要连接的表的所有行之后,将扫描缓冲区。
  • 缓冲区中没有被标记的每一行,通过NULL补充进行扩展(【要连接的表】的列设为NULL)。
批量键值访问连接(Batched Key Access Joins,BKA)

批量键值访问连接(Batched Key Access Joins,BKA)和BNL类似,将驱动表(外部表)的行/结果集存入连接缓冲区(join buffer),然后根据buffer中的数据批量地与内表的数据进行匹配,进而减少内层循环的扫描次数。

批量键值访问连接(BKA)时,可以通过索引访问内部表(第二个表)。 BKA可以用于内连接(inner join)、外连接(outer join)、半连接(semijoin )以及嵌套外连接(nested outer joins)。

批量键值访问连接(Batched Key Access Joins,BKA)的流程可以简要地概括为以下几个步骤:

  1. 将驱动表(外部表)的行/结果集存入连接缓冲区(join buffer)。
  2. BKA算法为缓冲区中的所有行构建用于访问要连接表(内表)的键值。
  3. 键值通过Multi-Range Read(MRR)接口提交给数据库引擎。
  4. MRR利用键值在索引中执行查找,并获取由这些键找到的连接表的记录(回表)。
  5. 返回匹配的数据给客户端。

参考: Batched Key Access Joins https://dev.mysql.com/doc/refman/8.0/en/bnl-bka-optimization.html#bka-optimization

Block Nested-Loop Join Algorithm https://dev.mysql.com/doc/refman/8.0/en/nested-loop-joins.html

MRR(Multi-Range Read)优化

MySQl MRR(Multi-Range Read)优化特性基本过程如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 - 进行范围扫描(Range Scans)的时候,MySQL首先只扫描索引获得索引元组(index tuples),并收集相关行的键值(主键Row Id)。
 - 根据键值(Row Id) 对索引元组(index tuples)排序,将排序结果存储到每个会话的内存缓存中(read_rnd_buffer_size 定义大小,默认256K)。
 - 根据键值(primary key)顺序从基表中返回数据(回表)

通过MRR可以减少随机磁盘读的次数,实现对基本表数据的更有序的扫描。

  • 对于InnoDB和MyISAM引擎的表,MRR优化支持索引范围扫描(index range scans )和等价连接(equi-join)等操作。
  • 对于NDB的表,MRR优化支持多范围索引扫描(multiple-range index scans)或通过属性执行等值连接(equi-join by an attribute)操作。
  • MRR优化不支持在虚拟列上创建的辅助索引(secondary indexes created on virtual generated columns)。

参考: 8.2.1.11 Multi-Range Read Optimization https://dev.mysql.com/doc/refman/8.0/en/mrr-optimization.html

通过EXPLAIN查看BKA 的使用

运行SQL时,可以使用EXPLAIN来查看MySQL优化器执行查询的计划,当一个表在查询执行计划中出现 “Using join buffer (Batched Key Access)” 这个提示,且该表的 type 列的值为 ref 或 eq_ref 时,就意味着该表使用了 BKA 算法。 BKA 算法可以有效地优化大表关联查询的性能,减少磁盘 I/O 和内存占用,提高查询速度。

哈希连接算法(hash join algorithm)

MySQL 8.0.18以后的版本中,MySQL可以用哈希连接算法(hash join algorithm)来进行表连接操作。 哈希连接通常要比嵌套循环连接更有效,特别是如果内存可以容纳其中一个表的情况下更加高效。

哈希连接算法(hash join algorithm)将连接操作分为两个阶段:构建哈希表和扫描哈希表。 在构建哈希表阶段,MySQL将连接操作的第一个表插入到哈希表中,其中哈希表的键是连接操作的连接列。 在扫描哈希表阶段,MySQL将连接操作的第二个表的每一行与哈希表中的相应行进行比较,如果它们的连接列匹配,则将它们作为连接操作的结果返回。

哈希连接示例

例如以下查询作为示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SELECT *
FROM t1
JOIN t2 ON t1.column1 = t2.column2;

在执行此查询时,MySQL将使用Hash Join算法来执行连接操作。

例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
--创建测试表
mysql> CREATE TABLE t1 (  id INT PRIMARY KEY,  column1 INT);
Query OK, 0 rows affected (0.84 sec)

mysql> CREATE TABLE t2 (  id INT PRIMARY KEY,  column2 INT);
Query OK, 0 rows affected (0.36 sec)

--插入示例数据
mysql> INSERT INTO t1 VALUES (1, 10), (2, 20), (3, 30), (4, 40), (5, 50);
Query OK, 5 rows affected (0.09 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysql> INSERT INTO t2 VALUES (1, 10), (2, 20), (3, 30), (4, 40), (5, 60);
Query OK, 5 rows affected (0.04 sec)
Records: 5  Duplicates: 0  Warnings: 0

--查看执行计划
mysql> explain format=tree
    -> SELECT *
    -> FROM t1
    -> JOIN t2 ON t1.column1 = t2.column2;
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                                                                                                   |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Inner hash join (t2.column2 = t1.column1)  (cost=3.50 rows=5)
    -> Table scan on t2  (cost=0.07 rows=5)
    -> Hash
        -> Table scan on t1  (cost=0.75 rows=5)
 |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)

mysql> explain
    -> SELECT *
    -> FROM t1
    -> JOIN t2 ON t1.column1 = t2.column2;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                                      |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    5 |   100.00 | NULL                                       |
|  1 | SIMPLE      | t2    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    5 |    20.00 | Using where; Using join buffer (hash join) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------------------+
2 rows in set, 1 warning (0.00 sec)

mysql>

具体来说,MySQL将按照以下步骤执行Hash Join:

  1. MySQL将从t1中读取所有行,并将它们插入到一个哈希表中,其中哈希表的键是连接列(在此示例中为column1)的值。
  2. MySQL将从t2中读取每一行,并将连接列的值用作哈希表的键来查找哈希表。如果哈希表中存在匹配的行,则将它们作为连接操作的结果返回。
  3. 如果哈希表中不存在匹配的行,则继续扫描t2中的下一行,直到所有行都被扫描完毕。
  4. 在explain执行计划中,通过Extra信息可以看到使用了哈希连接,例:【 Using where; Using join buffer (hash join) 】。

通过使用Hash Join算法,MySQL可以在内存中快速查找匹配的行,从而提高连接操作的性能。但是,如果t1非常大,那么构建哈希表可能会消耗大量的内存,从而导致性能下降。因此,在使用Hash Join算法时,需要根据实际情况评估内存使用情况,并根据需要调整MySQL的配置参数。

参考: 8.2.1.4 Hash Join Optimization https://dev.mysql.com/doc/refman/8.0/en/hash-joins.html

连接算法的选择

SQL查询连接算法的使用和选择,根据MySQL的版本演进也不断发生改变。

  1. MySQL 8.0.18之前的版本,无法使用索引的等值连接(equi-joins )会使用块嵌套循环连接(Block Nested-Loop Join Algorithm)。
  2. MySQL 8.0.18及更高的版本,无法使用索引的等值连接(equi-joins )会使用散列连接(hash join algorithm),当存在一个或多个可用于单表谓词的索引时,也可以使用哈希连接。
  3. MySQL 8.0.18版本,支持使用BNL/NO_BNL和HASH_JOIN/NO_HASH_JOIN提示来控制是否使用哈希连接;也支持通过设置optimizer_switch系统变量的hash_join=on/off参数来控制是否使用哈希连接
  4. MySQL 8.0.19及更高的版本,无法控制SQL查询是否使用哈希连接。
  5. MySQL 8.0.20之前的版本,如果连接的表对没有至少一个等值连接条件,则无法使用哈希连接,并且会使用较慢的块嵌套循环算法。
  6. MySQL 8.0.20及更高的版本,MySQL不再支持块嵌套循环连接,而是使用散列连接来代替所有的块嵌套循环连接的情况。
  7. MySQL 8.0.20及更高版本中,哈希连接也可以用于外连接(包括反连接和半连接)

参考: 【MySQL】控制MySQL优化器行为方法之optimizer_switch系统变量 Hash join in MySQL 8 https://dev.mysql.com/blog-archive/hash-join-in-mysql-8/

例题

例题1:关于哈希连接(Hash Joins)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Choose the best answer. Which condition is true about the use of the hash join algorithm?

A) At least one of the tables in the join must have a hash index. 
B) No index can be used for the join. 
C) The query must access no more than two tables. 
D) The smallest of the tables in the join must fit in memory as set by join_buffer_size.

例题1 解析

参考答案:B

1.无法使用索引的等值连接(equi-joins )会使用散列连接(hash join algorithm)

参考: https://dev.mysql.com/doc/refman/8.0/en/hash-joins.html

Beginning with MySQL 8.0.18, MySQL employs a hash join for any query for which each join has an equi-join condition, and in which there are no indexes that can be applied to any join conditions

2.多表连接也可以使用哈希连接算法。

3.哈希连接算法使用join_buffer_size系统变量控制可以使用的内存量,但不要求连接中最小的表必须适合内存。

例题2:EXPLAIN 执行计划

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Choose two. Which two methods can be used to determine whether a query uses the hash join algorithm?
A) EXPLAIN FORMAT=JSON
B) EXPLAIN FORMAT=TRADITIONAL
C) EXPLAIN FORMAT=TREE
D) EXPLAIN without any formatting argument
E) EXPLAIN ANALYZE

例题2 解析

参考答案:C E

但是根据如下的结果可以看到,EXPLAIN 的任何一个选项都可以看出执行计划是否使用了Hash Join。 如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
A)   "using_join_buffer": "hash join"
B)Using where; Using join buffer (hash join)
C)   Inner hash join
D)  Using where; Using join buffer (hash join)
E)   Inner hash join 

Explain各选项的结果如下:

A) EXPLAIN FORMAT=JSON
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mysql> EXPLAIN FORMAT=JSON
    -> SELECT *
    -> FROM t1
    -> JOIN t2 ON t1.column1 = t2.column2;
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| EXPLAIN                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| {
  "query_block": {
    "select_id": 1,
    "cost_info": {
      "query_cost": "3.50"
    },
    "nested_loop": [
      {
        "table": {
          "table_name": "t1",
          "access_type": "ALL",
          "rows_examined_per_scan": 5,
          "rows_produced_per_join": 5,
          "filtered": "100.00",
          "cost_info": {
            "read_cost": "0.25",
            "eval_cost": "0.50",
            "prefix_cost": "0.75",
            "data_read_per_join": "80"
          },
          "used_columns": [
            "id",
            "column1"
          ]
        }
      },
      {
        "table": {
          "table_name": "t2",
          "access_type": "ALL",
          "rows_examined_per_scan": 5,
          "rows_produced_per_join": 5,
          "filtered": "20.00",
          "using_join_buffer": "hash join",
          "cost_info": {
            "read_cost": "0.25",
            "eval_cost": "0.50",
            "prefix_cost": "3.50",
            "data_read_per_join": "80"
          },
          "used_columns": [
            "id",
            "column2"
          ],
          "attached_condition": "(`testdb`.`t2`.`column2` = `testdb`.`t1`.`column1`)"
        }
      }
    ]
  }
} |
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1 row in set, 1 warning (0.07 sec)

mysql>

B)EXPLAIN FORMAT=TRADITIONAL
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mysql> EXPLAIN FORMAT=TRADITIONAL
    -> SELECT *
    -> FROM t1
    -> JOIN t2 ON t1.column1 = t2.column2;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                                      |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    5 |   100.00 | NULL                                       |
|  1 | SIMPLE      | t2    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    5 |    20.00 | Using where; Using join buffer (hash join) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------------------+
2 rows in set, 1 warning (0.00 sec)

mysql>
C) EXPLAIN FORMAT=TREE
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mysql> EXPLAIN FORMAT=TREE
    -> SELECT *
    -> FROM t1
    -> JOIN t2 ON t1.column1 = t2.column2;
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                                                                                                   |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Inner hash join (t2.column2 = t1.column1)  (cost=3.50 rows=5)
    -> Table scan on t2  (cost=0.07 rows=5)
    -> Hash
        -> Table scan on t1  (cost=0.75 rows=5)
 |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql>

D) EXPLAIN
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mysql> EXPLAIN
    -> SELECT *
    -> FROM t1
    -> JOIN t2 ON t1.column1 = t2.column2;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                                      |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    5 |   100.00 | NULL                                       |
|  1 | SIMPLE      | t2    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    5 |    20.00 | Using where; Using join buffer (hash join) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+--------------------------------------------+
2 rows in set, 1 warning (0.00 sec)

mysql>
E) EXPLAIN ANALYZE
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mysql> EXPLAIN ANALYZE
    -> SELECT *
    -> FROM t1
    -> JOIN t2 ON t1.column1 = t2.column2;
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                                                                                                                                                                                                                                 |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| -> Inner hash join (t2.column2 = t1.column1)  (cost=3.50 rows=5) (actual time=0.103..0.108 rows=4 loops=1)
    -> Table scan on t2  (cost=0.07 rows=5) (actual time=0.014..0.017 rows=5 loops=1)
    -> Hash
        -> Table scan on t1  (cost=0.75 rows=5) (actual time=0.047..0.053 rows=5 loops=1)
 |
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

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

本文分享自 SQL和数据库技术 微信公众号,前往查看

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
浅析BMP位图文件结构(含Demo)
    关于BMP位图格式在网上可以找到比较详细的相关文档,有兴趣的可以搜索标题为“BMP文件结构的探索”的文章,可以在搜索结果中找到一个WORD文档,里面有很详细的介绍。很感谢这个文档的作者(ID是WhatIf),总结得很详细而且还附有详细的应用代码(文档我会放在本文最后面的附件部分)。因为文档中写得很详细,所以我在此就结合自己写的程序示例来介绍下位图的主要结构,用兴趣的可以将附件文件下载下来,结合本节给的相关测试代码进行学习和研究。下面直接引用其描述:
用户1170933
2022/05/10
7180
浅析BMP位图文件结构(含Demo)
vc++如何将客户区存为bmp和VC实现自绘图形输出到bmp文件
BOOL CTestestView::WriteWindowToDIB(LPTSTR szFile, CWnd *pWnd)
阳光岛主
2019/02/19
1.3K0
WinCE中解决“图片采集及压缩”问题的开发历程
   让WinCE工控板上的摄像头拍照,然后将图片数据通过GPRS发送到指定的主机数据库中。
用户1170933
2022/05/10
1.3K0
百问FB显示开发图像处理 - BMP图像处理
​ 前言:所有的图像文件,都是一种二进制格式文件,每一个图像文件,都可以通过解析文件中的每一组二进制数的含义来获得文件中的各种信息,如图像高度,宽度,像素位数等等。只是不同的文件格式所代表的二进制数含义不一样罢了。我们可以通过UltraEdit软件打开图像文件并查看里面的二进制数排列。
阿志小管家
2024/11/29
1590
百问FB显示开发图像处理 - BMP图像处理
YV12转RGB24的计算转换和bmp(dib)文件的显示保存
最近又接触到图像处理这一块,翻查到一年前自己写的代码http://blog.csdn.net/gongluck93/article/details/52813042,发现有点看不懂了! 所以自己又整理了一波(YV12转RGB24,显示和保存dib): #include "stdafx.h" /******************************************************************* * Copyright(c) 2017 * All rights rese
_gongluck
2018/03/09
1.4K0
【C】用C语言提取bmp图片像素,并进行K-means聚类分析——容易遇到的问题
关于bmp图片的格式,网上有很多文章,具体可以参考百度百科,也有例子程序。这里只提要注意的问题。 (1)结构体定义问题:首先按照百度百科介绍的定义了结构体,但是编译发现重定义BITMAPFILEHEADER等。其实只要包含了Windows.h,里面的wingdi.h就已经定义了处理bmp的结构体,故不需要自己再重复定义。 (2)读取文件的字节对其问题:要使用#pragma pack (1)来方便读取文件头的结构体,否则结构体的大小会由于字节对齐问题改变。不知是否头文件中已经使用了该宏,在我的代码中注释掉#p
ascii0x03
2018/04/12
2.6K0
RGB24,RGB565,RGB444图片质量比较
以下图片,第二幅是RGB24的原图。第一幅是对第二幅进行RGB444的有损变换图,第三幅是对第二幅进行RGB565的有损变换图。其中肉眼很难分辨RGB565和RGB24的差别。RGB444有明显噪点。
xiny120
2019/06/11
5.2K0
RGB24,RGB565,RGB444图片质量比较
ov7725 stm32_如何给实验培养皿拍照
平台:STM32ZET6(核心板)+ST-LINK/V2+SD卡+USB串口线+鹰眼OV7725摄像头(注意,为了减少摄像头连线的麻烦,建议初学者选取单片机时选用带有摄像头接口的板子)
全栈程序员站长
2022/11/09
6610
ov7725 stm32_如何给实验培养皿拍照
【第3版emWin教程】第18章 emWin6.x的2D图形库之绘制流位图(SPI Flash方案)
教程不断更新中:http://www.armbbs.cn/forum.php?mod=viewthread&tid=98429 第18章 emWin6.x的2D图形库之绘制流位图(SPI
Simon223
2021/06/29
8970
GDI编程
由于最近一直在搞GDI(GDI+)和图片处理的东西,怕自己忘记(其实已经忘得差不多),就仿照网上的BITMAPINFO查看器,写了个东西。 工程下载地址:点击打开链接 运行效果如图: 虽然比较(很)难
_gongluck
2018/03/08
1.3K0
GDI编程
Linux应用开发-libjpeg库交叉编译与使用
在开发板上如果想要显示jpeg格式的图片,必须用到libjpeg库,不可能自己去编写jpg的解码代码。
DS小龙哥
2022/05/09
3.9K0
Linux应用开发-libjpeg库交叉编译与使用
Win32/C# 应用不依赖任何库使用纯 GDI+ 对窗口截图(BitBlt)
在 Windows 上有 GDI+ 来操作位图,不止能完成很多的位图操作,还提供了与 Win32 窗口的互操作,可以截到 Win32 窗口的图片。
walterlv
2023/10/22
7930
VB.NET 直接读取CAD DWG文件转换成BMP位图进行预览
vb.net 直接从DWG文件中提取位图放在PictureBox中预览 Imports System.IO Public Class Form1 Private Sub Button1_Cl
办公魔盒
2019/07/22
4.2K1
VB.NET 直接读取CAD DWG文件转换成BMP位图进行预览
【第3版emWin教程】第17章 emWin6.x的2D图形库之绘制流位图(QSPI Flash内存映射方案)
教程不断更新中:http://www.armbbs.cn/forum.php?mod=viewthread&tid=98429 第17章 emWin6.x的2D图形库之绘制流位图(QSPI
Simon223
2021/06/29
8000
C++屏幕截图 图片转JPEG
C#实现同屏的时候,频繁截屏内存并不能很好的释放,所以就打算用C++实现这部分的功能。
码客说
2021/07/13
2.4K1
BMP文件解析_图片分析
BMP(全称Bitmap)是Window操作系统中的标准图像文件格式,可以分成两类:设备相关位图(DDB)和设备无关位图(DIB),使用非常广。它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BMP文件所占用的空间很大。BMP文件的图像深度可选lbit、4bit、8bit、16bit、24bit或者32bit。BMP文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。 由于BMP文件格式是Windows环境中交换与图有关的数据的一种标准,因此在Windows环境中运行的图形图像软件都支持BMP图像格式。
全栈程序员站长
2022/11/15
1.8K0
[2021]Linux下C语言qrencode二维码生成库的基本使用和ARM开发板移植
因为我们的嵌入式设备使用的是C语言,所以如何不想自己从头造轮子的话,就需要找一个比较合适的C语言的二维码生成的库。
手撕代码八百里
2021/08/10
3.7K0
深入探索视频帧中的颜色空间—— RGB 和 YUV
接触前端音视频之后,需要掌握大量音视频和多媒体相关的基础知识。在使用 FFmpeg + WASM 进行视频帧提取时,涉及到视频帧和颜色编码等相关概念。本文将对视频帧中的颜色空间进行介绍。 一、视频帧 对于视频,我们都知道是由一系列的画面在一个较短的时间内(通常是 1/24 或 1/30 秒)不停地下一个画面替换上一个画面形成连贯的画面变化。这些画面称之为视频帧。 对于视频帧,在现代视频技术里面,通常都是用 RGB 颜色空间或者 YUV 颜色空间的像素矩阵来表示。在 ffmpeg 里面,我们可以看到源码 li
用户1097444
2022/06/29
1.9K0
深入探索视频帧中的颜色空间—— RGB 和 YUV
C#中使用FreeImage库加载Bmp、JPG、PNG、PCX、TGA、PSD等25种格式的图像(源码)。
该文介绍了如何使用FreeImage库来读取、写入、显示、处理各种图像格式,并包含详细的代码示例。同时,还提供了关于图像处理工具和技术的一些思考,以及如何使用FreeImageNET库进行更高级的图像处理。
用户1138785
2018/01/03
2.9K0
C#中使用FreeImage库加载Bmp、JPG、PNG、PCX、TGA、PSD等25种格式的图像(源码)。
WPF开发-扫描仪Twain协议图片解析
Twain协议扫描图片的时候,图片是以Bitmap的格式存储在内存中,我们需要从内存中把图片给复制出来。
码客说
2024/06/09
2020
WPF开发-扫描仪Twain协议图片解析
推荐阅读
相关推荐
浅析BMP位图文件结构(含Demo)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验