【基础篇】ClickHouse 表引擎详解

文章目录

  • 0. 引言
  • 1. 什么是表引擎
  • 2. 不同表引擎使用场景
      • 1. MergeTree:
      • 2. Log:
      • 3. Memory:
      • 4. Distributed:
      • 5. Kafka:
      • 6. MaterializedView:
      • 7. File和URL:
  • 3. MergeTree 家族
      • 3.1. MergeTree:
      • 3.2. ReplacingMergeTree:
      • 3.3. SummingMergeTree:
      • 3.4. AggregatingMergeTree:
      • 3.5. CollapsingMergeTree:
      • 3.6. VersionedCollapsingMergeTree:
  • 4. Log 家族
      • 4.1. TinyLog:
      • 4.2. StripeLog:
      • 4.3. Log:
    • 5. Memory 和 File 家族
      • 5.1. Memory:
      • 5.1.2. File:
  • 6. Null 家族
  • 7. 外部数据表引擎(MySQL, HDFS, URL, etc.)
      • 7.1. MySQL:
      • 7.2. HDFS:
      • 7.3. URL:
  • 引擎类型
    • MergeTree {#mergetree}
    • 日志
    • 集成引擎 {#integration-engines}
    • 用于其他特定功能的引擎 {#yong-yu-qi-ta-te-ding-gong-neng-de-yin-qing}
  • 虚拟列
  • 参考文档

在这里插入图片描述

0. 引言

ClickHouse的一大特性就是其表引擎,表引擎决定了如何存储数据,以及如何处理对数据的读写操作。在ClickHouse中,每张表都由一个表引擎支持,而且在创建表的时候就需要指定其表引擎

ClickHouse有很多类型的表引擎,包括基于磁盘存储的表引擎如MergeTree系列(MergeTree、ReplacingMergeTree、SummingMergeTree等)、Log系列(TinyLog、StripedLog、Log)等,也有基于内存存储的表引擎如Memory。每种表引擎都有其适用的场景和特性,例如,MergeTree系列是最常用的表引擎,适用于大量数据的存储和分析,而Memory引擎则适用于存储少量临时数据。

了解和选择合适的表引擎是使用ClickHouse进行高效数据分析的关键。接下来,我们将详细介绍各种类型的表引擎,以及它们的应用场景和限制。

1. 什么是表引擎

表引擎(Table Engine)是一种数据库管理系统中的关键部分,负责存储数据、读取数据和处理数据查询。不同的表引擎具有不同的性能特性和适用范围。

在某些数据库系统中,例如MySQL,你可以为每个表选择不同的表引擎,包括InnoDB,MyISAM,Memory等。这些表引擎在功能、性能、并发能力、恢复能力等方面都有所不同。

在ClickHouse中,表引擎的选择将影响数据的存储格式、索引的使用、并发控制机制、是否支持数据复制等许多重要的方面。

表引擎(即表的类型)决定了什么

  • 数据的存储方式和位置,写到哪里以及从哪里读取数据
  • 支持哪些查询以及如何支持。
  • 并发数据访问。
  • 索引的使用(如果存在)。
  • 是否可以执行多线程请求。
  • 数据复制参数。

2. 不同表引擎使用场景

1. MergeTree:

说明:MergeTree是ClickHouse的主要表引擎,支持索引和数据分区,适用于大数据计算。

使用场景:适用于大数据分析,如用户行为分析、日志分析等。

示例:

CREATE TABLE example_merge_tree
(date Date,id UInt32,value String
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(date)
ORDER BY (date, id)
SETTINGS index_granularity = 8192;

2. Log:

说明:Log表引擎用于存储日志和其他机器数据。不支持索引和数据分区。

使用场景:适用于小数据量的日志和其他机器数据的存储。

示例:

CREATE TABLE example_log
(event_time DateTime,event_type String,event_data String
) ENGINE = Log;

3. Memory:

说明:Memory表引擎将所有数据存储在RAM中,适用于临时表和小数据量。

使用场景:适用于需要快速访问和计算的小数据量场景。

示例:

CREATE TABLE example_memory
(key UInt32,value String
) ENGINE = Memory;

4. Distributed:

说明:Distributed表引擎用于在多个节点间分布查询和数据。它自动分发查询和数据到所有节点。

使用场景:适用于需要在多个节点间进行数据分析的分布式场景。

示例:

CREATE TABLE example_distributed
(date Date,id UInt32,value String
) ENGINE = Distributed('my_cluster', 'my_database', 'example_merge_tree', rand());

5. Kafka:

说明:Kafka表引擎用于和Kafka集成,可用于实时数据流处理。

使用场景:适用于实时数据处理,如日志实时处理、实时数据分析等。

示例:

CREATE TABLE example_kafka
(event_time DateTime,event_type String,event_data String
) ENGINE = Kafka()
SETTINGSkafka_broker_list = 'localhost:9092',kafka_topic_list = 'test_topic',kafka_group_name = 'test_group',kafka_format = 'JSONEachRow',kafka_num_consumers = 2;

6. MaterializedView:

说明:MaterializedView引擎用于预处理数据,可以提高查询性能。

使用场景:适用于需要对大数据进行预处理以提高查询性能的场景。

示例:

CREATE MATERIALIZED VIEW example_mv
ENGINE = AggregatingMergeTree()
PARTITION BY toYYYYMM(date)
ORDER BY (date, id)
AS
SELECTdate,id,count() AS count
FROM example_merge_tree
GROUP BY date, id;

7. File和URL:

说明:File和URL表引擎用于对文件进行操作,例如CSV、Parquet等。

使用场景:适用于需要对文件进行操作的场景,如ETL操作、数据导入导出等。

示例:

CREATE TABLE example_file
(id UInt32,value String
) ENGINE = File(CSV, '/path/to/your/csv_file.csv');CREATE TABLE example_url
(id UInt32,value String
) ENGINE = URL('http://example.com/data.csv', CSV);

3. MergeTree 家族

ClickHouse的MergeTree家族引擎是一组支持实时数据更新、查询和数据合并功能的表引擎。这些引擎为大数据场景提供了高性能的解决方案。以下是MergeTree家族的主要成员及其使用场景。
MergeTree家族引擎根据不同的业务场景提供了多种实时数据处理功能,为大数据场景下的实时计算提供了强大的支持。在进行数据建模时,可以根据具体需求选择合适的MergeTree引擎。

3.1. MergeTree:

说明:MergeTree是ClickHouse的基本表引擎,支持索引和数据分区。

使用场景:适用于大数据分析,如用户行为分析、日志分析等。

示例:

CREATE TABLE example_merge_tree
(date Date,id UInt32,value String
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(date)
ORDER BY (date, id)
SETTINGS index_granularity = 8192;

3.2. ReplacingMergeTree:

说明:ReplacingMergeTree用于实时删除重复数据。当合并过程中发现相同的主键数据时,只保留最新的一条记录。

使用场景:适用于需要实时删除重复数据的场景,如实时去重、数据清洗等。

示例:

CREATE TABLE example_replacing_merge_tree
(date Date,id UInt32,value String
) ENGINE = ReplacingMergeTree()
PARTITION BY toYYYYMM(date)
ORDER BY (date, id)
SETTINGS index_granularity = 8192;

3.3. SummingMergeTree:

说明:SummingMergeTree用于实时对数值型字段进行求和。在合并过程中,具有相同主键的记录将被合并为一条记录,并对指定字段求和。

使用场景:适用于需要对数值型字段进行实时求和的场景,如计数器、流量统计等。

示例:

CREATE TABLE example_summing_merge_tree
(date Date,id UInt32,value UInt32
) ENGINE = SummingMergeTree(value)
PARTITION BY toYYYYMM(date)
ORDER BY (date, id)
SETTINGS index_granularity = 8192;

3.4. AggregatingMergeTree:

说明:AggregatingMergeTree用于实时对数据进行聚合。在合并过程中,具有相同主键的记录将被聚合为一条记录,根据指定的聚合函数进行计算。

使用场景:适用于需要实时聚合数据的场景,如统计、报表等。

示例:

CREATE TABLE example_aggregating_merge_tree
(date Date,id UInt32,value UInt32,countState AggregateFunction(count)
) ENGINE = AggregatingMergeTree()
PARTITION BY toYYYYMM(date)
ORDER BY (date, id)
SETTINGS index_granularity = 8192;

3.5. CollapsingMergeTree:

说明:CollapsingMergeTree用于实时删除重复数据。不同于ReplacingMergeTree,它使用一个名为Sign的列来表示记录的状态(1表示插入,-1表示删除)。在合并过程中,符号相反且其他列相同的记录会被抵消。

使用场景:适用于需要实时删除重复数据的场景,如数据同步、状态更新等。

示例:

CREATE TABLE example_collapsing_merge_tree
(date Date,id UInt32,value String,sign Int8
) ENGINE = CollapsingMergeTree(sign)
PARTITION BY toYYYYMM(date)
ORDER BY (date, id)
SETTINGS index_granularity = 8192;

3.6. VersionedCollapsingMergeTree:

说明:VersionedCollapsingMergeTree与CollapsingMergeTree类似,但它还使用一个名为Version的列来表示记录的版本。在合并过程中,版本较新的记录会覆盖版本较旧的记录。

使用场景:适用于需要实时删除重复数据并支持版本控制的场景,如数据历史记录、状态更新等。

示例:

CREATE TABLE example_versioned_collapsing_merge_tree
(date Date,id UInt32,value String,sign Int8,version UInt32
) ENGINE = VersionedCollapsingMergeTree(sign, version)
PARTITION BY toYYYYMM(date)
ORDER BY (date, id)
SETTINGS index_granularity = 8192;

4. Log 家族

ClickHouse的Log家族引擎是一组专门用于大数据日志处理的表引擎。这些引擎能够快速地处理大量日志数据,并以极高的性能对其进行查询。以下是Log家族的主要成员及其使用场景。

4.1. TinyLog:

说明:TinyLog是一种非常简单的引擎,它将所有列保存在一个文件中。不支持索引,所以查询速度较慢,但是插入速度快。

使用场景:适用于小型数据集和日志记录。

示例:

CREATE TABLE example_tinylog
(date Date,id UInt32,value String
) ENGINE = TinyLog;

4.2. StripeLog:

说明:StripeLog在存储结构上类似于TinyLog,但是数据分为几个部分(stripes)进行存储,每个stripe对应一个块(block)。不支持索引。

使用场景:适用于较大的日志记录。

示例:

CREATE TABLE example_stripelog
(date Date,id UInt32,value String
) ENGINE = StripeLog;

4.3. Log:

说明:Log是一种简单的引擎,它把每一列的数据分别存储在不同的文件中。不支持索引,适用于大量的日志数据。

使用场景:适合大量的日志记录和流数据。

示例:

CREATE TABLE example_log
(date Date,id UInt32,value String
) ENGINE = Log;

总结:Log家族引擎特别适合处理大量的日志数据,能够以极高的效率插入和查询数据。但是由于这些引擎不支持索引,所以查询性能会比MergeTree家族的引擎要差一些。在进行数据建模时,可以根据数据量和查询需求选择合适的Log引擎。

5. Memory 和 File 家族

ClickHouse中的Memory和File家族引擎分别用于在内存和文件系统中存储数据。以下是Memory和File家族的主要成员及其使用场景。

5.1. Memory:

说明:Memory引擎将所有数据存储在内存中。它支持实时查询,并且具有极高的查询速度。但是,由于它将所有数据保存在内存中,因此在服务器重启或崩溃时,数据会丢失。

使用场景:适用于需要快速查询的小型数据集,如缓存、临时表或实时分析。

示例:

CREATE TABLE example_memory
(date Date,id UInt32,value String
) ENGINE = Memory;

5.1.2. File:

说明:File引擎将数据保存在服务器的文件系统中。它支持将数据存储为各种文件格式(如CSV、Parquet、JSON等)。File引擎不支持索引,因此查询速度较慢。

使用场景:适用于需要将数据以特定文件格式存储的场景,如ETL操作、数据备份或离线分析。

示例:

CREATE TABLE example_file
(date Date,id UInt32,value String
) ENGINE = File(CSV);

总结:Memory和File家族引擎分别用于内存和文件系统中的数据存储。Memory引擎具有非常高的查询速度,适用于实时查询,但数据在服务器重启或崩溃时会丢失。File引擎适用于需要将数据存储为特定文件格式的场景,但查询速度较慢。在进行数据建模时,可以根据数据存储需求和查询需求选择合适的Memory或File引擎。

6. Null 家族

Null家族是ClickHouse中的一个特殊的表引擎家族,它基本上不会执行任何操作或存储任何数据。以下是Null家族的主要成员及其使用场景:

  1. Null:

说明:Null引擎不保存数据,并且不对数据进行任何操作。当你往这个表里面插入数据时,数据会被直接丢弃。对于从这个表中的查询,它总是返回一个空结果。

使用场景:Null引擎主要用于调试或测试,例如,你可能想要测试插入或查询的性能,而不实际保存任何数据。另一个常见用例是作为一个"黑洞"表,用来快速丢弃不需要的数据。

示例:

CREATE TABLE example_null
(date Date,id UInt32,value String
) ENGINE = Null;

总结:Null家族引擎基本上不执行任何操作,也不保存任何数据。尽管Null引擎在生产环境中的应用可能有限,但在调试和测试中可能很有用。

7. 外部数据表引擎(MySQL, HDFS, URL, etc.)

ClickHouse支持外部数据表引擎,这些引擎可以让你以类似于操作本地表的方式访问外部数据源。以下是一些常见的外部数据表引擎及其特点:

7.1. MySQL:

说明:MySQL表引擎允许你将MySQL数据库中的数据表作为ClickHouse本地表进行操作。这使得你可以方便地在ClickHouse中查询MySQL表数据。

使用场景:当你需要在ClickHouse中查询MySQL中的数据时,MySQL表引擎非常有用。

示例:

CREATE TABLE mysql_table
(id UInt32,name String,age UInt8
) ENGINE = MySQL('host:port', 'database_name', 'table_name', 'user', 'password');

7.2. HDFS:

说明:HDFS表引擎可以让你将Hadoop分布式文件系统(HDFS)中的数据表作为ClickHouse本地表进行操作。它支持各种文件格式,如Parquet、ORC、Avro等。

使用场景:当你需要在ClickHouse中查询HDFS中的数据时,HDFS表引擎非常有用。

示例:

CREATE TABLE hdfs_table
(id UInt32,name String,age UInt8
) ENGINE = HDFS('hdfs://host:port/path/to/data/file.parquet', 'Parquet');

7.3. URL:

说明:URL表引擎可以让你将远程文件(通过HTTP或HTTPS访问)作为ClickHouse本地表进行操作。它支持各种文件格式,如CSV、TSV、JSON等。

使用场景:当你需要在ClickHouse中查询远程文件中的数据时,URL表引擎非常有用。

示例:

CREATE TABLE url_table
(id UInt32,name String,age UInt8
) ENGINE = URL('https://example.com/data.csv', 'CSV', 'id UInt32, name String, age UInt8');

总结:外部数据表引擎可以让你方便地访问外部数据源,如MySQL、HDFS或URL等。这使得在ClickHouse中整合和查询多种数据源变得简单。


引擎类型

MergeTree {#mergetree}

适用于高负载任务的最通用和功能最强大的表引擎。这些引擎的共同特点是可以快速插入数据并进行后续的后台数据处理。 MergeTree系列引擎支持数据复制(使用Replicated* 的引擎版本),分区和一些其他引擎不支持的其他功能。

该类型的引擎:

  • MergeTree
  • ReplacingMergeTree
  • SummingMergeTree
  • AggregatingMergeTree
  • CollapsingMergeTree
  • VersionedCollapsingMergeTree
  • GraphiteMergeTree

日志

具有最小功能的轻量级引擎。当您需要快速写入许多小表(最多约100万行)并在以后整体读取它们时,该类型的引擎是最有效的。

该类型的引擎:

  • TinyLog
  • StripeLog
  • Log

集成引擎 {#integration-engines}

用于与其他的数据存储与处理系统集成的引擎。
该类型的引擎:

  • Kafka
  • MySQL
  • ODBC
  • JDBC
  • HDFS

用于其他特定功能的引擎 {#yong-yu-qi-ta-te-ding-gong-neng-de-yin-qing}

该类型的引擎:

  • Distributed
  • MaterializedView
  • Dictionary
  • Merge
  • File
  • Null
  • Set
  • Join
  • URL
  • View
  • Memory
  • Buffer

虚拟列

虚拟列是表引擎组成的一部分,它在对应的表引擎的源代码中定义。

您不能在 CREATE TABLE 中指定虚拟列,并且虚拟列不会包含在 SHOW CREATE TABLEDESCRIBE TABLE 的查询结果中。虚拟列是只读的,所以您不能向虚拟列中写入数据。

如果想要查询虚拟列中的数据,您必须在SELECT查询中包含虚拟列的名字。SELECT * 不会返回虚拟列的内容。

若您创建的表中有一列与虚拟列的名字相同,那么虚拟列将不能再被访问。我们不建议您这样做。为了避免这种列名的冲突,虚拟列的名字一般都以下划线开头。

参考文档

  1. Yandex ClickHouse官方文档: https://clickhouse.tech/
  2. ClickHouse表引擎介绍: https://clickhouse.tech/docs/en/engines/table-engines/
  3. ClickHouse的表引擎选择: https://www.jianshu.com/p/752c1f8b38e7
  4. ClickHouse的数据存储和计算原理: https://www.jianshu.com/p/a1d3d6e1f76a
  5. ClickHouse表引擎深入理解: https://zhuanlan.zhihu.com/p/142616461

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

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

相关文章

理解HTTPS/TLS/SSL(二)可视化TLS握手过程并解密加密数据

文章目录 WireShark抓包TLS握手过程Client HelloServer HelloEncryped Extenstions, Certificate, Certificate VerifyChange Ciper Spec, FinshedTLS 1.2和TLS 1.3的区别能不能在进一步? 解密WireShark中抓到的TLS包参考资料 上一篇文章已经在本地使用了生成自签名…

【Linux操作系统】信号的产生捕获

🔥🔥 欢迎来到小林的博客!!       🛰️博客主页:✈️林 子       🛰️博客专栏:✈️ Linux       🛰️社区 :✈️ 进步学堂       &#x1f6f0…

The driver has not received any packets from the server

在测试数据迁移时遇到的错误。 目录 一、错误 二、解决 三、数据迁移测试 3.1 环境 3.2 源码及测试 3.2.1 源码 3.2.2 测试结果(太慢) 3.2.3 源码修改 3.2.4 异常及解决 一、错误 The driver has not received any packets from the server. 二…

数学建模——微分方程介绍

一、基础知识 1、一阶微分方程 称为一阶微分方程。y(x0)y0为定解条件。 其常规求解方法: (1)变量分离 再两边积分就可以求出通解。 (2)一阶线性求解公式 通解公式: 有些一阶微分方程需要通过整体代换…

四种常用的自动化测试框架

一直想仔细研究框架,写个流水账似的测试程序不难,写个低维护成本的测试框架就很难了,所以研究多种测试框架还是很有必要的,知道孰优孰劣,才能在开始编写框架的时候打好基础,今天读到了KiKi Zhao的翻译文章&…

Java实现Ip地址获取

Java实现Ip地址获取 一、两种实现方式二、测试结果 一、两种实现方式 package com.lyp;import org.apache.commons.lang3.ObjectUtils;import java.net.*; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Optional;/***…

Linux Ubuntu20.04深度学习环境快速配置命令记录

一、驱动安装 1、更新系统包 sudo apt-get updatesudo apt-get upgrade 2、安装显卡驱动 使用apt方式安装驱动,多数情况不容易成功, 使用一下方法更佳: 1.查看合适显卡的驱动版本 ubuntu-drivers devices NVIDIA GeForce 驱动程序 - …

git压缩仓库

git 压缩仓库 git gc命令压缩增量存储单元,节省磁盘空间 du -sh 查看当前文件夹占用多少K 快照的存储: 对于修改的内容,做快照处理并保存. 对于未修改的文件,做引用处理.

SOLIDWORKS Composer位置关键帧的使用

SOLIDWORKS Composer是专业的SOLIDWORKS及3D文件处理的动画制作软件,作为SOLIDWORKS 产品线下的一个明星存在。 SOLIDWORKS Composer几乎可以处理任何SOLIDWORKS的模型文件并将之转化成可以动作的机械动画,可以引用在企业的网站、产品说明书以及工作指导…

MySQL 面试题——MySQL 基础

目录 1.什么是 MySQL?有什么优点?2.MySQL 中的 DDL 与 DML 是分别指什么?3.✨数据类型 varchar 与 char 有什么区别?4.数据类型 BLOB 与 TEXT 有什么区别?5.DATETIME 和 TIMESTAMP 的异同?6.✨MySQL 中 IN …

STM32F4X SPI W25Q128

STM32F4X SPI W25Q128 什么是SPISPI的特点SPI通信引脚SPI接线方式SPI速率SPI通信方式SPI时钟相位和时钟极性 STM32F4X SPISTM32F4X SPI配置STM32F4X SPI频率 W25Q128W25Q128存储结构W25Q128读写操作W25Q128常用指令读取ID命令(0x90)写使能命令(0x06)禁止写使能命令(0x04)读取W2…

黑马JVM总结(七)

(1)StringTable_编译器优化 “a”“b”对应#4:是去常量池中找ab的这个符号 astore 5:是把这个存入编号为5的局部变量 “ab”对应的指令 #4,跟“a”“b”对应#4下面弄是一样的 在执行s3“ab”这行个代码时&#xf…

在PHP8中向数组添加元素-PHP8知识详解

在php8中向数组添加元素有多种方法,在这里主要讲解几个常用的方法:使用方括号[]添加元素、使用array_unshift()函数,向数组的头部添加元素、使用array_push()函数,向数组的尾部添加元素、使用array_splice()函数添加元素。 1、使用…

学习Bootstrap 5的第十三天

目录 提示框 如何创建提示框 实例 指定提示框的位置 实例 弹出框 如何创建弹出框 实例 指定弹出框的位置 实例 关闭弹出框 实例 提示框 提示框是一个小小的弹窗,在鼠标移动到元素上显示,鼠标移到元素外就消失。 如何创建提示框 Bootstrap…

LeetCode 332. Reconstruct Itinerary【欧拉回路,通路,DFS】困难

本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章…

Vue3+ElementUI使用

<!DOCTYPE html> <html> <head><meta charset"UTF-8"><meta name"viewport" content"initial-scale1.0,maximum-scale1.0,minimum-scale1.0,user-scalable0, widthdevice-width"/><!-- 引入样式 --><lin…

【C++】list的模拟实现【完整理解版】

目录 一、list的概念引入 1、vector与list的对比 2、关于struct和class的使用 3、list的迭代器失效问题 二、list的模拟实现 1、list三个基本函数类 2、list的结点类的实现 3、list的迭代器类的实现 3.1 基本框架 3.2构造函数 3.3 operator* 3.4 operator-> 3…

bug总结问题集和知识点集(一)

目录 一 bug问题集1. 端口被占用 二 oracle1. oracle查看版本怎么操作2. oracle数据库&#xff1a;参数个数无效![在这里插入图片描述](https://img-blog.csdnimg.cn/6a2eebc164f9406c81525371893bbd11.png)3. ORACLE数据库如何完整卸载? 三 mybatis1. mybatis用注解如何实现模…

学习Node js:raw-body模块源码解析

raw-body是什么 raw-body的主要功能是处理HTTP请求体的原始数据。它提供了以下核心功能&#xff1a; 解析请求体&#xff1a;可以从HTTP请求中提取原始数据&#xff0c;包括文本和二进制数据。配置选项&#xff1a;通过配置项&#xff0c;可以设置请求体的大小限制、编码方式…

【LeetCode-简单题KMP】232. 用栈实现队列

文章目录 题目方法一&#xff1a;用输入栈和输出栈模拟队列 题目 方法一&#xff1a;用输入栈和输出栈模拟队列 只有输出栈为空的时候才能将输入栈的元素补充到输出栈&#xff0c;否则输出栈不为空&#xff0c;如果再从输入栈往输出栈填充元素&#xff0c;就会弄乱队列的先进先…