为什么MatrixOne 0.5变慢了?

Leapfrog Triejoin:最坏情况下的最优连接算法 介绍 leapfrog triejoin是商业数据记录系统 LogicBlox® 采用的一种新颖的连接算法,在不同的基准测试中表现出色。leapfrog triejoin论文的写作者认为这个算法,即使在完全连接的最坏情况下也能提供最优解,是NPRR算法(另外一个最坏情况下join优化算法)的竞争对手,并且leapfrog triejoin算法容易学习和实现,结论证明很简单。 论文地址:Leapfrog Triejoin: A Worst-case Optimal Join Algorithm – Log 阅读详情

近期关心MatrixOne的小伙伴有反馈,MatrixOne 0.5的性能比之前慢了不少。在今年初MatrixOne 0.2版本的发布文章中,还有MatrixOne的SSB单表性能超过ClickHouse,并且多表性能达到Starrocks的报道,为什么到了0.5反而变慢了呢?
留意当初报道的小伙伴应当会注意到因子化加速引擎的字样,事实上,正是得益于0.2版本中因子化引擎,才使得基于Golang语言实现的MPP计算引擎在性能上能够不落下风,并且在某些场景下碾压其他大多数OLAP数据库,比如非主键Join。那么为什么到了0.5版本,所谓的因子化引擎不再提及,性能也由此慢下来了呢? 这一切均需要从因子化引擎本身来谈起。

因子化是个莫名其妙的称呼,但是也只能这么翻译,因为它的全称叫Factorisation,如果伙伴们回滚到MatrixOne 0.4及其之前的版本,更是可以看到所有的聚合函数都在一个叫做Ring的莫名其妙的目录下。那么什么叫Factorisation,Ring又是什么呢?
在这里插入图片描述
这是来自于DBToaster一族著名的增量物化视图算法,它把数据库的一张表看作由乘积和加法构成的表示,而Ring则代表在这种由乘法和加法构成的表示中满足交换律、结合律和分配律的系列操作,比如各种Count/Sum/Avg/Max等等的聚合函数,就满足Ring的要求。在此基础之上,因子化定义了3种基础操作:Union,Join,Marginalization,如下图所示。前两者比较容易理解,最后一个Marginalization,翻译过来叫边缘化,其实质相当于对一个由加法和乘法构成的表示,基于某列(图中是A列)做提取公因数操作,类似分配律,因此才有因子化引擎的叫法。
在这里插入图片描述
在这里插入图片描述

给定以上三种操作,现假设需要计算Select count(*) From R(A,B) Natural Join S(A,C,E) Natural Join T(C,D),Join关系如下图所示:

在这里插入图片描述

假定R,S,T三张表的大小都为N,那么朴素的实现,复杂度则为O(N3)O(N^3)O(N3) ,既将三张表完成Join后,再进行count的计算。在因子化计算中,有了Marginalization操作,我们就可以把聚合函数下推:

在这里插入图片描述

这里V1[A]V_1[A]V1​[A]代表对R基于B列做边缘化操作的结果。进一步边缘化,得到V2[A,C]V_2[A,C]V2​[A,C]:

在这里插入图片描述

最后得到:

在这里插入图片描述

在以上不断Marginalization计算的过程中,聚合函数一直不断下推,因此尽管有3表Join,但是中间结果一直保持最小,不存在朴素实现那种生成巨大的Join结果后才进行聚合实现的问题,这就是为什么基于因子化引擎计算Join时,即使是非主键Join,也无所畏惧,不用担心Join产生的笛卡尔积从而OOM的问题。因此,从本质上来说,因子化引擎,提供了一种通用的聚合下推的计算框架。任何聚合函数,只要它满足交换律和结合律,就可以实现其对应的Marginalization操作,然后在统一的聚合下推框架中得到应用。

以上查询中,每次边缘化所操作的属性叫做Variable,给定查询进行边缘化操作的顺序叫做Variable Order,系列边缘化操作可以组成一棵树,叫做View Tree。这里可以看到用到了View字眼,是因为,如果把View Tree上的这些View物化,那这就是一个物化视图的维护算法。

在这里插入图片描述

因子化计算引擎,对于查询是有限制的,Variable只能为Group By和Join属性,且根据以上的因式分解可以很容易看出来,它也只能支持等值Join。因此,简单的讲,因子化计算的第一大主要功能,就是一个用于CAQ(Conjunctive Aggregation Query)查询的计算框架,在查询包含等值Inner Join或者Group By,以及聚合函数时,它提供了一种统一的聚合下推框架,使得计算的中间状态最小化,因此是非常理想的计算加速手段。下图的例子对一个通用查询做了因子化拆解:

在这里插入图片描述

聚合下推并不是稀罕事,尽管并不是所有的SQL计算引擎都支持,比如Presto也是到了最近几年才支持这个功能,它显然是一种查询加速的有效手段。只是相比之下,一般的SQL计算引擎需要对不同的聚合函数采用不同的策略,因为并不存在一个统一的聚合下推方法,比如AVG跟SUM的下推方式就不一样。因此在因子化框架之下,只需要根据Ring的语义实现对应Agg函数的接口,即可完成在CAQ查询下的聚合下推。

因子化引擎的第二大功能,是推出了一个较优的Join Order框架——基于Hyper Graph的Hyper Tree分解算法,该算法来自于知名的Worst Cast Optimal Join系列,意思是在最坏情况下,该Join算法的复杂度可以最优。这一族算法区别于标准SQL引擎里对Join的处理流程——以表为单元处理每一次Join操作,该算法则是以属性(列)为单元处理每次Join。我们知道,标准的SQL计算引擎,基本都是两表Join——根据左深或者右深的原则,很少会有多路Join,因为即使是两表Join,它的搜索空间复杂度也会达到N!N!N!,至于Bushy Plan(下图的右侧),它的搜索空间更加巨大,很难得到一个哪怕是局部最优解,即使是左深Plan,在表多的情况下,也因为计算复杂度常常无法搜索到全局最优,而只能用一个次优解来替代。

在这里插入图片描述

假设有下图的三张表R1,R2,R3R_1,R_2,R_3R1​,R2​,R3​,以及对应的属性A1,A2,A3A_1,A_2,A_3A1​,A2​,A3​。如果采用标准的Binary Join,我们可以采用基于A2A_2A2​的Hash Join把R1,R2R_1,R_2R1​,R2​首先连接,这样就把R1R_1R1​中的(1,x)和(5,x)与R2R_2R2​中的(x,2)和(x,4)连接,此时输出的数据是4个三元组:(1,x,2),(1,x,4),(5,x,2)和(5,x,4),记录(1,q)则没有匹配因此不输出。为了进一步完成Join,需要继续探测其他的表属性,直到所有可能的关系都被探测完,但这可能非常慢。假如每个表的长度都为N,那么反复做Binary Join所输出的Tuple数量会在O(N2)O(N^2)O(N2)级。因此这时就需要一个聪明的计划,形成一棵二叉树,其中叶子是关系,内部节点对应关系的连接。树的根节点代表所有关系的连接,树状结构建议哪些关系可以连接在一起。例如刚才的例子中,如果R2R_2R2​和R3R_3R3​首先连接,那么在与R1R_1R1​连接之前只产生两条记录。Worst Case Optimal Join系列算法,就是一种能够确保产生的Tuple数量可以达到O(N3/2)O(N^{3/2})O(N3/2)级的算法,在数学上证明是这最低的。

在这里插入图片描述

Worst Case Optimal Join包含一系列算法,例如LeapFrog TrieJoin,NPRR等,因子化也是其中的一种,它基于超图表达每个查询,超图中的每个节点定义为上文中的Variable,把查询中每个关系的Variable集,是图的一条(超)边ϵ\epsilonϵ。例如针对R1(A,B),R2(A,c),R3(B,c)R_1(A,B),R_2(A,c),R_3(B,c)R1​(A,B),R2​(A,c),R3​(B,c)的三角Join,超图如下图表示,这里Variable集合包含{A,B,C},超边集合包含{{A,B},{A,C},{B,C}}。

在这里插入图片描述

因子化提出了一种基于超图的树分解(Hyper Tree Deecomposition)算法,树分解定义为对超图(V,ϵ)(V,\epsilon)(V,ϵ)的一个变换,它将图分解为一个Pair (T,x),其中T代表一棵树,x代表一个函数,将T中每个节点映射到V的一个子集,称为bag。树分解满足2个特性:覆盖性——T需要包含所有超边;连通性——所有的V形成一棵连通的子树。下图右侧,就是针对上述查询的一个树分解结果。

在这里插入图片描述

树分解算法,其目的就是找到一个合适的Variable Order(前文中有提到),因为Variable Order可以表达为一个Pair (F,key),其中F是一个有根的树,查询Q中的每个Variable都对应树的一个节点;key是一个函数,将每个Variable映射到它在F中的祖先Variable的子集。通过Variable Order决定View Tree的结构,就决定了整个查询中Join Order和执行的框架。

因此,因子化就是满足CAQ查询条件的Join Order和Agg下推的计算框架。在MatrixOne 0.2的代码中,实现了因子化的Variable Order和View Tree系列算法,使得对于SSB这样简单的查询,可以达到性能最优;在MatrixOne 0.4的代码中,实现了树分解算法,使得对于任意表Join,都能给出相对不错的性能。这听起来不错,那么为什么这些实现从MatrixOne 0.5拿掉了呢?

通过上面的介绍,大家也可以看出,整个因子化是一个非常另类的计算框架——它没有逻辑计划,直接就进入执行了,而且只能按照它的逻辑来,伴随着一堆莫名其妙的术语比如Variable/View Tree/Ring等等,这么一个怪异的框架,使得它在支持更为丰富的SQL功能的时候,很难处理,比如MatrixOne在0.5一开始定下的目标就是在两个多月内跑通TPCH,如果要继续使用因子化,就需要做个IF ELSE——如果满足CAQ条件,那么执行因子化逻辑,否则就是标准流程——例如TPCH必备的子查询,CTE,非等值JOIN,未来的窗口函数等等。

因此,MatrixOne的研发同学们,从0.5版本开始,又把SQL计算引擎,从Parser后开始的部分,按照标准的MPP实现重新做了一份,包含逻辑计划,优化器以及执行器,仅仅历时两个多月就跑通了TPCH。

目前,MatrixOne已经进入0.6迭代周期,在这个周期中,需要对这套标准的SQL执行引擎做加速,包含子查询,各种非等值Join,Runtime Filtering,Join Order(传统左深树),使得它能够跟其他MPP引擎相提并论。那么因子化是否还会回到MatrixOne?这并不困难,因为加入它只是个IF ELSE,我们需要首先确保标准的SQL引擎工作高效;其次,在前文已经提到过,它来自于IVM算法,而MatrixOne已经喊出了HSTAP的口号,或许对于S(Streaming)来说,才是因子化算法的舞台。

欢迎对这一族看起来比较黑科技的算法感兴趣的同学,一同加入MO大家庭来一起把计算引擎(含S)变得更加高效和独一无二。

【Tableau】解决订阅报表PDF中文显示为乱码(方框)问题 一、问题描述 在tableau server网页端报表中文字符能正常显示,但在订阅后发送到邮箱时,以图片格式呈现的内容中中文字符显示为方框。 网页端报表能正常显示中文字符: 邮件中的报表不能正常显示中文字符: 二、问题分析 网页端字符显示情况是由html编码决定的,而tableau生成图片时是通过所部署的服务器的字体文件显示字体。因此可能是由于Linux服务器缺失相关的字体文件导致网页端选择的中文字体在服务器上缺失对应的字体文件导致的。则考虑在服务器引入对应的字体文件。 三、问题解决 1、查看服务器现有 阅读详情

相关推荐

Pyrosim进阶指南:从隧道火灾模拟到复杂通风策略分析

本文深入探讨Pyrosim在隧道火灾模拟与通风策略分析中的高级应用。从精确几何建模到火源参数设置,再到通风系统的量化分析,详细介绍了如何利用Pyrosim优化隧道安全设计。特别强调了临界风速验证、横向通风配置及结果可视化技巧,为工程师提供实用的进阶指南。

weixin_30644369的博客 140

【Java】Fel计算引擎学习

#Fel是轻量级的高效的表达式计算引擎Fel在源自于企业项目,设计目标是为了满足不断变化的功能需求和性能需求。Fel是开放的,引擎执行中的多个模块都可以扩展或替换。Fel的执行主要是通过函数实现,运算符(+、-等都是Fel函数),所有这些函数都是可以替换的,扩展函数也非常简单。Fel有双引擎,同时支持解释执行和编译执行。可以根据性能要求选择执行方式。编译执行就是将表达式编译成字节码(生成java代码和编译模块都是可以扩展和替换的)##Fel有多快?http。//负责提供气象服务的上下文环境。...

哈士奇 1万+

【从零开始玩量化1】AKShare: Python开源财经数据接口库

文章目录量化的第一步:数据AKShare介绍AKShare安装AKShare使用AKTools安装/使用结语 量化的第一步:数据 想要玩量化,第一步要有数据,这个数据可能是历史交易数据、财务数据、宏观数据等等。我们最终要做的,无非就是从数据中分析出有价值的信息,以便用来指导投资策略。 在获取数据的这条道路上,我走了很多弯路,尝试了各种方法:使用Tushare到放弃、自己写网易股票页面的爬虫,自己写申万行业数据的爬虫、自己写同花顺问财的爬虫、使用聚宽的免费数据API等等,直到最终,我发现了AKShare。 A

量化投资助手的博客 5万+

连接定义点作用_最坏情况下最优连接(Worst-Case Optimal Joins)

所谓最坏情况下最优连接(Worst-Case Optimal Joins),是一项关于数据库中连接操作的最新技术。给定若干表{R1, R2, ..., Rn},在它们之上的多表连接所能得到结果的数量上限可以根据它们的连接所对应超图(hypergraph)的部分边覆盖(fractional edge cover)来确定。所谓超图H=(V(H), E(H)),就是图中每条边可以有多个端点,而不再是常用...

weixin_35572715的博客 759

智能座舱音频系统集成与调试:从芯片选型到音质优化实战

在智能座舱域控制器架构中,音频系统已从简单的功放加扬声器演进为SoC、数字音频总线、外部DSP与多通道功放协同的复杂子系统。TDM总线的时隙分配、PDM麦克风阵列的信号完整性,以及AEC回声消除算法如何与硬件协同,直接决定多音区体验和语音交互的可靠性。工程实践中,音频调试的关键在于先理顺供电、接地、时钟与数据路由,再针对功放削波、采样率失配、TDM slot错位等典型问题进行系统性排查。从芯片选型到系统级指标验收,只有将音频链路视为整车电子电气架构的一个协同整体,才能真正实现从“响”到“好听”的跨越。本文结

weixin_30162121的博客 372

批量读取_MCGS触摸屏如何实现批量读取modbus数据的方法?

前两天,在一个QQ群里,有同行的朋友问,在MCGS中如何实现批量读取数据,因为他当时面临设备,通讯协议才是MODBUS RTU,同时厂家说地址不能分开读,必须是连续的。鉴于他提供的消息是能够设置的地方都试过了。为此,我直接告诉通过脚本,批量读取的方案。那么这个方案究竟如何实现?且看我下面慢慢道来。一、工具1.modsim:仿真PLC或者第三方设备。2.MCGS组态软件3.串口软件:在电脑中生成两不...

weixin_32511509的博客 8162

Leapfrog algorithm

Leapfrog演算法 在提及Leapfrog演算法之前,我們先使用泰勒展開解析速度和位置的關係: (1)  利用泰勒展開式把v(t)在+δt/2和-δt/2展開,如式1和式2。 (2)  將式1和式2整理後,可得速度項算式3。 (3)  利用泰勒展開式把r(t)和r(t+δt)在t+δt/2展開,如式4和式5。 (4)  將式4和式5整理後,可得位置項算式6。 式3和式6即所謂的

alaclp的专栏 3863

上位机图像处理和嵌入式模块部署(开篇)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 图像处理是现实生活当中很实用的一门技术。工业上一般采用的是机器视觉,以传统算法和光源控制为主,部分采用了深度学习技术。而生活当中,则主要以二维码识别、人脸识别、车牌识别和ocr识别为主,这中间深度学习与AI扮演了很重要的角色。过去,市场上的商业收费软件,主要还是以传统设备厂商提供的上位机软件为主,那这一部分是不是结合最新的npu技术,应该做出一些新的东西出来呢?

嵌入式-老费,一个分享专业嵌入式知识的blog 1338

并发数据结构Leapfrog Probing

Leapfrog Probing一个hash table是用来存取一系列key/value对,有很多方式用来实现一个hash table。但是都有一个共同点就是桶,每一个hash table都会包含一系列的桶,对于每一个key来说都会唯一的属于一个桶。为了决定某个key是属于哪个桶,你需要对这个key进行hash,然后对它取模,其余数就是这个key所属于的桶下标,整个过程如下图:不可避免的,最终会有

zyfforlinux 3025

【DRAM存储器五十六】LPDDR5介绍--WCK2CK Leveling和Read gate training

简述LPDDR5 WCK2CK leveling和read gate traning基本原理与操作步骤

highman110的博客 8795

C#串口通信从入门到精通(5)——打开、关闭串口

本文详细介绍如何打开串口

qq_34059233的博客 6786

MatrixOne 0.2.0性能测试报告

最新发布的MatrixOne 0.2.0版本新增了Benchmarks章节,针对常规测试程序SSB与纽约出租车数据测试,在向量化执行引擎和因子化加速技术的加持之下,MatrixOne在查询速度方面表现突出,可以承载TB级别数据的快速查询,与同类数据库产品相比有较明显的优势。

MatrixOrigin的博客 3933

基于Vision Transformer的鸟类图像分类(200个类别)完整代码+数据

基于Vision Transformer的鸟类图像分类(200个类别)完整代码+数据

1728

MatrixOne从入门到实践03——部署MatrixOne

前两章节我们简单介绍了MatrixOne和源码编译了MatrixOne。本章节将使用不同的部署方式,来部署MatrixOne的服务。

MatrixOrigin的博客 7071

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

MatrixOne实战系列回顾 | MatrixOne 集群运维

为大家带来本次MatrixOne 实战直播系列第四部分集群运维。本次将从四个方向为大家演示MatrixOne的功能。分别是版本升降、集群扩缩、集群调优以及最后的QA环节。首先我们采用替换二进制文件进行单机版MatrixOne版本的升降。从 0.8.0 版本开始,MatrixOne 所有后续版本都将与 0.8.0 版本的底层数据存储格式保持兼容,各个版本间可以平滑升降级(低于0.8.0版本无法使用这种方式进行升降级)。MatrixOne 只有一个二进制程序包,对于单机版本我们可以非常方便的通过手动替换 mo-

MatrixOrigin的博客 1152

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

MatrixOne 1.1.0 Release

我们非常高兴地宣布: MatrixOne内核1.1.0版本 正式发布啦!

MatrixOrigin的博客 1166

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

MatrixOne从入门到实战04——MatrixOne的连接和建表

前几篇文章,为大家介绍了MatrixOne这个产品,以及编译、部署MatrixOne的服务。本章主要讲述如何使用不同方式连接MatrixOne以及进行表的创建。

MatrixOrigin的博客 1104

MatrixOne 0.2.0 发布 | 最快的SQL计算引擎来了~

在数月的打磨和努力开发之下,MatrixOne 0.2版本正式发布啦!

MatrixOrigin的博客 1630

MatrixOne部署完全指南:从Docker到Kubernetes的5种方案

MatrixOne作为一款AI原生的HTAP数据库,支持多种灵活的部署方案,无论是本地开发还是生产环境都能轻松应对。本文将详细介绍5种实用的MatrixOne部署方法,帮助您快速上手这款强大的Git-for-Data数据库系统。😊 ## 📊 MatrixOne部署方案概览 在开始具体部署之前,让我们先了解MatrixOne支持的5种主要部署方式: | 部署方案 | 适用场景 | 复杂度

gitblog_01140的博客 910

MatrixOne WAL设计解析

为了保证Log Backend中的LSN基本有序,乱序的跨度不要太大,维持了一个逻辑LSN的窗口,如果有很早的log entry正在写入还未成功,会停止向Log Backend写入新的entry。例如,如果窗口的长度是7,图中的LSN为13的entry还未返回,就会阻塞住LSN大于等于20的entry。比如图中逻辑truncate到7,这条entry对应Log Backend中的11,但是Log Backend中5,6,7,10对应的逻辑LSN都大于7,不能被truncate。更新操作被拆分成插入和删除。

MatrixOrigin的博客 185

手把手入门MO | 如何使用 Flink 将批量数据写入 MatrixOne

得益于其独特的架构设计,用户可以降低多达70%的硬件和运维成本,增加3-5倍的开发效率,同时更加灵活的响应市场需求变化和更加高效的抓住创新机会。在下面的命令中,使用 --topic 参数指定要添加到的主题,而 --bootstrap-server 参数指定了 Kafka 服务的监听地址。创建 Person.java 和 Mysql2Mo.java 类,使用 Flink 读取 MySQL 数据,执行简单的 ETL 操作(将 Row 转换为 Person 对象),最终将数据写入 MatrixOne 中。

MatrixOrigin的博客 1214

干货分享 | MatrixOne系统架构

随着数字化转型的深入,数据价值也愈发凸显,数据技术出现了融合的趋势,基于客户的真实痛点,矩阵起源推出了超融合MatrixOne HSTAP数据库。MatrixOne 使数据数据库同时具备 TP、AP和Streaming三种能力,帮助客户彻底打破数据孤岛问题,成为企业智能化核心的数据基础设施。今天的分享将解析新一代超融合异构云原生数据库 MatrixOne 刚刚发布的0.5版本和后续版本的架构设计。

MatrixOrigin的博客 898

手把手入门MO | 如何使用 DolphinScheduler 连接 MatrixOne

MatrixOne 支持与可视化 DAG 工作流任务调度系统 DolphinScheduler 进行连接。本文将指导您如何通过 DolphinScheduler 连接到 MatrixOne 并创建任务工作流。

MatrixOrigin的博客 1113

MatrixOne从入门到实战06——视图实践

MatrixOne 也支持视图功能,且其与MySQL中的视图概念及语法非常类似。MatrixOne的视图也是一种虚拟存在的表,其行和列的数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的,只保存了sql逻辑,不保存查询结果。

MatrixOrigin的博客 313

MatrixOne从入门到实践02——源码编译

详解MatrixOne如何进行源码编译。

MatrixOrigin的博客 270

MatrixOne从入门到实践07——MO-Tester

MO-Tester 是基于 Java 语言进行开发,用于 MatrixOne 的测试套件。MO-Tester 构建了一整套完整的工具链来进行 SQL 自动测试。它包含测试用例和运行结果。MO-Tester 启动后,MO-Tester 将使用 MatrixOne 运行所有 SQL 测试用例,并将所有输出 SQL 测试结果与预期结果进行比较。所有案例的结果无论成功或者失败,都将记录在报告中。

MatrixOrigin的博客 811
上一篇: 关于TAE(Transactional Analytical Engine)的那些事
下一篇: 干货分享 | MatrixOne系统架构
MatrixOrigin
博客等级 码龄5年 708粉丝 230原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值