精华内容
下载资源
问答
  • 14级网络综述 — 主干网络篇

    千次阅读 2021-07-30 00:44:43
    点击上方“3D视觉工坊”,选择“星标”干货第时间送达作者丨VincentLee来源丨晓飞的算法工程笔记编辑丨极市平台导读早期的卷积神经很少考虑参数和计算的问题,由此轻级网络诞生,...

    点击上方“3D视觉工坊”,选择“星标”

    干货第一时间送达

    作者丨VincentLee

    来源丨晓飞的算法工程笔记

    编辑丨极市平台

    导读

     

    早期的卷积神经很少考虑参数量和计算量的问题,由此轻量级网络诞生,其旨在保持模型精度基础上近一步减少模型参数量和复杂度。本文对主要的轻量级网络进行了简述,让大家对轻量级网络的发展历程以及种类有更加清晰的了解。

    轻量级网络的核心是在尽量保持精度的前提下,从体积和速度两方面对网络进行轻量化改造,本文对轻量级网络进行简述,主要涉及以下网络:

    • SqueezeNet系列

    • ShuffleNet系列

    • MnasNet

    • MobileNet系列

    • CondenseNet

    • ESPNet系列

    • ChannelNets

    • PeleeNet

    • IGC系列

    • FBNet系列

    • EfficientNet

    • GhostNet

    • WeightNet

    • MicroNet

    SqueezeNet系列

    SqueezeNet系列是比较早期且经典的轻量级网络,SqueezeNet使用Fire模块进行参数压缩,而SqueezeNext则在此基础上加入分离卷积进行改进。虽然SqueezeNet系列不如MobieNet使用广泛,但其架构思想和实验结论还是可以值得借鉴的。

    SqueezeNet

    SqueezeNet是早期开始关注轻量化网络的研究之一,使用Fire模块进行参数压缩。

    SqueezeNet的核心模块为Fire模块, 结构如图 1 所示, 输入层先通过squeeze卷积层   卷 积)进行维度压缩,然后通过expand卷积层   卷积和   卷积混合)进行维度扩展。Fire模 块包含 3 个参数, 分别为squeeze层的   卷积核数  , expand层的   卷积核数   和   层的   卷积核数  , 一般

    SqueezeNext

    SqueezeNext是SqueezeNet实战升级版,直接和MobileNet对比性能。SqueezeNext全部使用标准卷积,分析实际推理速度,优化的手段集中在网络整体结构的优化。

    SqueezeNext的设计沿用残差结构,没有使用当时流行的深度分离卷积,而是直接使用了分离卷积,设计主要基于以下策略:

    • Low Rank Filters   低秩分解的核心思想就是将大矩阵分解成多个小矩阵,这里使用CP分解(Canonical Polyadic Decomposition), 将   卷积分解成   和   的分离卷积, 参数量能从   降为   。

    • Bottleneck Module   参数量与输入输出维度有关,虽然可以使用深度分离卷积来减少计算量,但是深度分离卷积在终端系统的计算并不高效。因此采用SqueezeNet的squeeze层进行输入维度的压缩,每个block的开头使用连续两个squeeze层,每层降低1/2维度。

    • Fully Connected Layers   在AlexNet中,全连接层的参数占总模型的96%,SqueezeNext使用bottleneck层来降低全连接层的输入维度,从而降低网络参数量。

    ShuffleNet系列

    ShuffleNet系列是轻量级网络中很重要的一个系列,ShuffleNetV1提出了channel shuffle操作,使得网络可以尽情地使用分组卷积来加速,而ShuffleNetV2则推倒V1的大部分设计,从实际出发,提出channel split操作,在加速网络的同时进行了特征重用,达到了很好的效果。

    ShuffleNet V1

    ShuffleNet的核心在于使用channel shuffle操作弥补分组间的信息交流,使得网络可以尽情使用pointwise分组卷积,不仅可以减少主要的网络计算量,也可以增加卷积的维度。

    在目前的一些主流网络中,通常使用pointwise卷积进行维度的降低,从而降低网络的复杂度,但由于输入维度较高,pointwise卷积的开销也是十分巨大的。对于小网络而言,昂贵的pointwise卷积会带来明显的性能下降,比如在ResNext unit中,pointwise卷积占据了93.4%的计算量。为此,论文引入了分组卷积,首先探讨了两种ShuffleNet的实现:

    • 图1a是最直接的方法,将所有的操作进行了绝对的维度隔离,但这会导致特定的输出仅关联了很小一部分的输入,阻隔了组间的信息流,降低了表达能力。

    • 图1b对输出的维度进行重新分配,首先将每个组的输出分成多个子组,然后将每个子组输入到不同的组中,能够很好地保留组间的信息流。

    图1b的思想可以简单地用channel shuffle操作进行实现,如图1c所示, 假设包含   组的卷积 层输出为   维,首先将输出reshape()为  , 然后进行transpose 0 , 最后再flatten()回   维。

    ShuffleNet V2

    ShuffleNetV1的pointwise分组卷积以及bottleneck结果均会提高MAC,导致不可忽视的计算损耗。为了达到高性能以及高准确率,关键是在不通过稠密卷积以及过多分组的情况下,获得输入输出一样的大维度卷积。ShuffleNet V2从实践出发,以实际的推理速度为指导,总结出了5条轻量级网络的设计要领,并根据要领提出了ShuffleNetV2,很好地兼顾了准确率和速度,其中channel split操作十分亮眼,将输入特征分成两部分,达到了类似DenseNet的特征重用效果。

    ShuffeNetV1的unit结构如图3ab所示, 在V1的基础上加入channel split操作, 如图3c所示。在每个unit的开头, 将特征图分为   以及   两部分,一个分支直接往后传递,另一个分支包 含3个输入输出维度一样的卷积。V2不再使用分组卷积, 因为unit的开头已经相当于进行了分 组卷积。在完成卷积操作后,将特征concate, 恢复到unit的输入大小, 然后进行channel shuffle操作。这里没有了element-wise adddition操作,也节省了一些计算量,在实现的时候将concat/channel shuffle/channel split合在一起做了,能够进一步提升性能。  空间下采样时对unit进行了少量的修改,如图3d所示,去掉了channel split操作,因此输出大小降低一倍,而维度则会增加一倍。

    MnasNet

    论文提出了移动端的神经网络架构搜索方法,该方法主要有两个思路,首先使用多目标优化方法将模型在实际设备上的耗时融入搜索中,然后使用分解的层次搜索空间让网络保持层多样性的同时,搜索空间依然很简洁,MnasNet能够在准确率和耗时中有更好的trade off

    MobileNet系列

    MobileNet系列是很重要的轻量级网络家族,出自谷歌,MobileNetV1使用深度可分离卷积构建轻量级网络,MobileNetV2提出创新的inverted residual with linear bottleneck单元,虽然层数变多了,但是整体网络准确率和速度都有提升,MobileNetV3则结合AutoML技术与人工微调进行更轻量级的网络构建。

    MobileNetV1

    MobileNetV1基于深度可分离卷积构建了非常轻量且延迟小的模型,并且可以通过两个超参数进一步控制模型的大小,该模型能够应用到终端设备中,具有很重要的实践意义。

    MobileNet通过深度可分离卷积优进行计算量优化,将标准卷积转化为深度卷积和pointwise卷积,每层后面都会接BN和ReLU。

    MobileNetV2

    MobileNetV2首先表明高维特征实际可以用紧凑的低维特征表达,然后提出了新的层单元inverted residual with linear bottleneck,该结构与残差网络单元类似,都包含shorcut,区别在于该结构是输入输出维度少,中间通过线性卷积先扩展升维,然后通过深度卷积进行特征提取,最后再映射降维,可以很好地保持网络性能且网络更加轻量。

    MobileNetV3

    MobileNetV3先基于AutoML构建网络,然后进行人工微调优化,搜索方法使用了platform-aware NAS以及NetAdapt,分别用于全局搜索以及局部搜索,而人工微调则调整了网络前后几层的结构、bottleneck加入SE模块以及提出计算高效的h-swish非线性激活。

    CondenseNet

    DenseNet基于特征复用,能够达到很好的性能,但是论文认为其内在连接存在很多冗余,早期的特征不需要复用到较后的层。为此,论文基于可学习分组卷积提出CondenseNet,能够在训练阶段自动稀疏网络结构,选择最优的输入输出连接模式,并在最后将其转换成常规的分组卷积分组卷积结构。

    分组卷积的学习包含多个阶段,前半段训练过程包含多个condensing阶段,结合引导稀疏化的正则化方法来反复训练网络,然后将不重要的filter剪枝。后半部分为optimization阶段,这个阶段对剪枝固定后的网络进行学习。

    ESPNet系列

    ESPNet系列的核心在于空洞卷积金字塔,每层具有不同的dilation rate,在参数量不增加的情况下,能够融合多尺度特征,相对于深度可分离卷积,深度可分离空洞卷积金字塔性价比更高。另外,HFF的多尺度特征融合方法也很值得借鉴 。

    ESPNet

    ESPNet是用于语义分割的轻量级网络,核心在于ESP模块。如图a所示,该模块包含point-wise卷积和空洞卷积金字塔,分别用于降低计算复杂度以及重采样有效感受域不同的特征。ESP模块比其它卷积分解方法(mobilenet/shufflenet)更高效,ESPNet能在GPU/笔记本/终端设备上达到112FPS/21FPS/9FPS。

    另外,论文发现,尽管空洞卷积金字塔带来更大的感受域,但直接concate输出却会带来奇怪网格纹路。为了解决这个问题,论文提出图b的HFF操作,在concate之前先将输出进行层级相加。相对于添加额外的卷积来进行后处理,HFF能够有效地解决网格纹路而不带来过多的计算量。另外,为了保证网络的梯度传递,在ESP模块添加了一条从输入到输出的shortcut连接。

    ESPNetV2

    ESPNetv2在ESPNet的基础上结合深度分离卷积的设计方法,进行了进一步的模型轻量化。首先将point-wise卷积替换为分组point-wise卷积,然后将计算量较大的空洞卷积替换为深度可分离空洞卷积,最后依然使用HFF来消除网格纹路,输出特征增加一次特征提取,得到图b的结构。考虑到单独计算K个point-wise卷积等同于单个分组数为K的point-wise分组卷积,而分组卷积的在实现上更高效,于是改进为图c的最终结构。

    ChannelNets

    论文提出channel-wise卷积的概念,将输入输出维度的连接进行稀疏化而非全连接,区别于分组卷积的严格分组,以类似卷积滑动的形式将输入channel与输出channel进行关联,能够更好地保留channel间的信息交流。基于channel-wise卷积的思想,论文进一步提出了channel-wise深度可分离卷积,并基于该结构替换网络最后的全连接层+全局池化的操作,搭建了ChannelNets。

    PeleeNet

    基于DenseNet的稠密连接思想,论文通过一系列的结构优化,提出了用于移动设备上的网络结构PeleeNet,并且融合SSD提出目标检测网络Pelee。从实验来看,PeleeNet和Pelee在速度和精度上都是不错的选择。

    IGC系列

    IGC系列网络的核心在分组卷积的极致运用,将常规卷积分解成多个分组卷积,能够减少大量参数,另外互补性原则和排序操作能够在最少的参数量情况下保证分组间的信息流通。但整体而言,虽然使用IGC模块后参数量和计算量降低了,但网络结构变得更为繁琐,可能导致在真实使用时速度变慢。

    IGCV1

    Interleaved group convolution(IGC)模块包含主分组卷积和次分组卷积,分别对主分区和次 分区进行特征提取, 主分区通过输入特征分组获得, 比如将输入特征分为   个分区, 每个分区 包含   维特征,而对应的次分区则分为   个分区, 每个分区包含   维特征。主分组卷积负责对输入特征图进行分组特征提取, 而次组卷积负责对主分组卷积的输出进行融合, 为   卷 积。IGC模块形式上与深度可分离卷积类似,但分组的概念贯穿整个模块, 也是节省参数的关键,另外模块内补充了两个排序模块来保证channel间的信息交流。

    IGCV2

    IGCV1通过两个分组卷积来对原卷积进行分解,减少参数且保持完整的信息提取。但作者发现,因为主分组卷积和次分组卷积在分组数上是互补的,导致次卷积的分组数一般较小,每个分组的维度较大,次卷积核较为稠密。为此,IGCV2提出Interleaved Structured Sparse Convolution,使用多个连续的稀疏分组卷积来替换原来的次分组卷积,每个分组卷积的分组数都足够多,保证卷积核的稀疏性。

    IGCV3

    基于IGCV和bootleneck的思想,IGCV3结合低秩卷积核和稀疏卷积核来构成稠密卷积核,如图1所示,IGCV3使用低秩稀疏卷积核(bottleneck模块)来扩展和输入分组特征的维度以及降低输出的维度,中间使用深度卷积提取特征,另外引入松弛互补性原则,类似于IGCV2的严格互补性原则,用来应对分组卷积输入输出维度不一样的情况。

    FBNet系列

    FBNet系列是完全基于NAS搜索的轻量级网络系列,分析当前搜索方法的缺点,逐步增加创新性改进,FBNet结合了DNAS和资源约束,FBNetV2加入了channel和输入分辨率的搜索,FBNetV3则是使用准确率预测来进行快速的网络结构搜索。

    FBNet

    论文提出FBNet,使用可微神经网络搜索(DNAS)来发现硬件相关的轻量级卷积网络,流程如图1所示。DNAS方法将整体的搜索空间表示为超网,将寻找最优网络结构问题转换为寻找最优的候选block分布,通过梯度下降来训练block的分布,而且可以为网络每层选择不同的block。为了更好地估计网络的时延,预先测量并记录了每个候选block的实际时延,在估算时直接根据网络结构和对应的时延累计即可。

    FBNetV2

    DNAS通过训练包含所有候选网络的超网来采样最优的子网,虽然搜索速度快,但需要耗费大量的内存,所以搜索空间一般比其它方法要小,且内存消耗和计算量消耗随搜索维度线性增加。为了解决这个问题,论文提出DMaskingNAS,将channel数和输入分辨率分别以mask和采样的方式加入到超网中,在带来少量内存和计算量的情况下,大幅增加 倍搜索空间。

    FBNetV3

    论文认为目前的NAS方法大都只满足网络结构的搜索,而没有在意网络性能验证时的训练参数的设置是否合适,这可能导致模型性能下降。为此,论文提出JointNAS,在资源约束的情况下,同时搜索最准确的训练参数以及网络结构。FBNetV3完全脱离了FBNetV2和FBNet的设计,使用的准确率预测器以及基因算法都已经在NAS领域有很多应用,主要亮点在于将训练参数加入到了搜索过程中,这对性能的提升十分重要。

    EfficientNet

    论文对模型缩放进行深入研究,提出混合缩放方法,该方法可以更优地选择宽度、深度和分辨率的维度缩放比例,从而使得模型能够达到更高的精度。另外,论文通过NAS神经架构搜索提出EfficientNet,配合混合缩放方法,能够使用很少量的参数达到较高的准确率。

    GhostNet

    训练好的网络一般都有丰富甚至冗余的特征图信息来保证对输入的理解,相似的特征图类似于对方的ghost。但冗余的特征是网络的关键特性,论文认为与其避免冗余特征,不如以一种cost-efficient的方式接受,于是提出能用更少参数提取更多特征的Ghost模块,首先使用输出很少的原始卷积操作(非卷积层操作)进行输出,再对输出使用一系列简单的线性操作来生成更多的特征。这样,不用改变其输出的特征图数量,Ghost模块的整体的参数量和计算量就已经降低了。

    WeightNet

    论文提出了一种简单且高效的动态生成网络WeightNet,该结构在权值空间上集成了SENet和CondConv的特点,在激活向量后面添加一层分组全连接,直接产生卷积核的权值,在计算上十分高效,并且可通过超参数的设置来进行准确率和速度上的trade-off。

    MicroNet

    论文提出应对极低计算量场景的轻量级网络MicroNet,包含两个核心思路Micro-Factorized convolution和Dynamic Shift-Max,Micro-Factorized convolution通过低秩近似将原卷积分解成多个小卷积,保持输入输出的连接性并降低连接数,Dynamic Shift-Max通过动态的组间特征融合增加节点的连接以及提升非线性,弥补网络深度减少带来的性能降低。

    本文亮点总结

    1.ShuffleNet系列是轻量级网络中很重要的一个系列,ShuffleNetV1提出了channel shuffle操作,使得网络可以尽情地使用分组卷积来加速,而ShuffleNetV2则推倒V1的大部分设计,从实际出发,提出channel split操作,在加速网络的同时进行了特征重用,达到了很好的效果。

    2.FBNet系列是完全基于NAS搜索的轻量级网络系列,分析当前搜索方法的缺点,逐步增加创新性改进,FBNet结合了DNAS和资源约束,FBNetV2加入了channel和输入分辨率的搜索,FBNetV3则是使用准确率预测来进行快速的网络结构搜索。

    本文仅做学术分享,如有侵权,请联系删文。

    下载1

    在「3D视觉工坊」公众号后台回复:3D视觉即可下载 3D视觉相关资料干货,涉及相机标定、三维重建、立体视觉、SLAM、深度学习、点云后处理、多视图几何等方向。

    下载2

    在「3D视觉工坊」公众号后台回复:3D视觉github资源汇总即可下载包括结构光、标定源码、缺陷检测源码、深度估计与深度补全源码、点云处理相关源码、立体匹配源码、单目、双目3D检测、基于点云的3D检测、6D姿态估计源码汇总等。

    下载3

    在「3D视觉工坊」公众号后台回复:相机标定即可下载独家相机标定学习课件与视频网址;后台回复:立体匹配即可下载独家立体匹配学习课件与视频网址。

    重磅!3DCVer-学术论文写作投稿 交流群已成立

    扫码添加小助手微信,可申请加入3D视觉工坊-学术论文写作与投稿 微信交流群,旨在交流顶会、顶刊、SCI、EI等写作与投稿事宜。

    同时也可申请加入我们的细分方向交流群,目前主要有3D视觉CV&深度学习SLAM三维重建点云后处理自动驾驶、多传感器融合、CV入门、三维测量、VR/AR、3D人脸识别、医疗影像、缺陷检测、行人重识别、目标跟踪、视觉产品落地、视觉竞赛、车牌识别、硬件选型、学术交流、求职交流、ORB-SLAM系列源码交流、深度估计等微信群。

    一定要备注:研究方向+学校/公司+昵称,例如:”3D视觉 + 上海交大 + 静静“。请按照格式备注,可快速被通过且邀请进群。原创投稿也请联系。

    ▲长按加微信群或投稿

    ▲长按关注公众号

    3D视觉从入门到精通知识星球:针对3D视觉领域的视频课程(三维重建系列三维点云系列结构光系列手眼标定相机标定orb-slam3等视频课程)、知识点汇总、入门进阶学习路线、最新paper分享、疑问解答五个方面进行深耕,更有各类大厂的算法工程人员进行技术指导。与此同时,星球将联合知名企业发布3D视觉相关算法开发岗位以及项目对接信息,打造成集技术与就业为一体的铁杆粉丝聚集区,近2000星球成员为创造更好的AI世界共同进步,知识星球入口:

    学习3D视觉核心技术,扫描查看介绍,3天内无条件退款

     圈里有高质量教程资料、可答疑解惑、助你高效解决问题

    觉得有用,麻烦给个赞和在看~  

    展开全文
  • 在线QQ客服:1922638专业的SQL Server、MySQL数据库同步软件关联是使用SELECT 操作表的SQL语言的一种操作机制,用于联系个或多个表。 SELECT是SQL中的查询语句,用于查询数据库中的数据。将SELECT和关联结合起来会...

    bc3f9276acf88283a0569b9b9ef9ee92.png

    在线QQ客服:1922638

    专业的SQL Server、MySQL数据库同步软件

    关联是使用SELECT 操作表的SQL语言的一种操作机制,用于联系两个或多个表。 SELECT是SQL中的查询语句,用于查询数据库中的数据。将SELECT和关联结合起来会产生一个关联的查询。

    假设一个班级有30名学生,则每个学生都有自己的姓名,学生编号,班级,班主任等。可以发现,每个班级的姓名和学生编号是唯一的,班主任,班主任电话和其他信息由学生共享。现在,如果您要将此类的信息存储在数据库中,则有两种存储方法。

    ①创建一个表,并将数据存储在该表中,如下所示。

    班主任

    课堂教师电话

    学生姓名

    学生证

    六年制

    阿福

    13131313131

    年轻人

    1

    六年制

    阿福

    13131313131

    大熊熊

    2

    六年制

    阿福

    13131313131

    静香

    3

    ②创建多个表并在分类后存储数据,如下所示。

    (1)

    班主任

    课堂教师电话

    六年制

    阿福

    13131313131

    (2)

    学生姓名

    学生证

    年轻人

    1

    六年制

    大熊熊

    2

    六年制

    静香

    3

    六年制

    为了便于说明,将不会编写30个学生信息。可以发现,将数据存储在表中可以提高读取表的可读性,但是开发人员会非常麻烦,因为表中的前三列信息完全相同。如果有30条数据,则开发人员必须重复填写相同的信息,这样麻烦就会出错。从方法②看,它对开发人员非常友好,只重复一列。并且方法②的优点在于,如果教师改变了手机号码,则只需要修改表(1)中的手机号码,而不是像方法①那样一一修改。方法②很方便,那么如何查询这样的表呢?

    现在,我们在实际数据库中设计两个表。为了方便SQL操作,我们将列的键设置为英文字母。

    (1)类信息构建代码

    老师

    移动

    六年制

    阿福

    13131313131

    (2)学生信息构建代码

    名称

    id

    年轻人

    1

    六年制

    大熊熊

    2

    六年制

    静香

    3

    六年制

    现在我们需要查看ID为1的学生信息

    执行结果如下

    老师

    移动

    名称

    id

    六年制

    阿福

    13131313131

    年轻人

    1

    76f927b8979dba220a95cc768c874bbb.png

    上面的结果实际上在数据库操作过程中分为以下三个步骤:

    (1)建立笛卡尔积

    该语句指定classinfo和stuinfo这两个表之间的关联,并且系统根据这两个表生成笛卡尔乘积。根据此笛卡尔积生成的表,我认为是这样的:

    老师

    移动

    名称

    id

    六年制

    阿福

    13131313131

    年轻人

    1

    六年制

    阿福

    13131313131

    大熊熊

    2

    六年制

    阿福

    13131313131

    静香

    3

    为了更直观地表示笛卡尔积

    classinfo现在更改为

    老师

    移动

    六年制

    阿福

    13131313131

    六年级的第二堂课

    True

    12121212121

    这时,获得了classinfo和stuinfo的笛卡尔积,结果如下。

    老师

    移动

    名称

    id

    六年制

    阿福

    13131313131

    年轻人

    1

    六年制

    阿福

    13131313131

    大熊

    2

    六年制

    阿福

    13131313131

    静香

    3

    六年级的第二堂课

    True

    12121212121

    年轻人

    1

    六年级的第二堂课

    True

    12121212121

    大熊

    2

    六年级的第二堂课

    True

    12121212121

    静香

    3

    如您所见,进行笛卡尔运算实际上是通过行乘法关联两个表,使一列具有相同的名称。

    (2)过滤器

    通过此过滤语句,系统挑选出classinfo.class和stuinfo.class中具有相同键值的行,并且id列中的键值是1。过滤后,系统会生成一个中间表,该中间表不是对用户可见。

    老师

    移动

    名称

    id

    六年制

    阿福

    13131313131

    年轻人

    1

    (3)选择并返回给用户

    这时,SELECT选择如上,返回的表如下。

    老师

    移动

    名称

    六年制

    阿福

    13131313131

    年轻人

    这时,您可以获得学生编号为1的学生的所有信息。

    假设现在有了第三个表,该表存储了班主任的年龄和性别信息,我们期望得到以下结果:

    老师

    移动

    年龄

    性别

    名称

    id

    每六年一堂课

    阿福

    13131313131

    31

    男性

    年轻人

    1

    那么我们如何使用SELECT获得这样的结果?

    在这里,我们必须了解多表关联的工作机制。像两个表一样,多表查询实际上是按顺序组合要查询的表,然后生成两个表和第三个表的笛卡尔积,最后根据过滤和选择操作用户返回结果。

    第三个表语句如下。

    老师

    年龄

    性别

    阿福

    31

    男性

    True

    35

    男性

    白雪

    25

    女性

    如上所述,将生成一个3X2X3笛卡尔表,然后对其进行过滤,选择并返回给用户。

    操作语句如下。

    最终结果如下所示。

    f11bc3ffa9d3a63e4960f0293baeeea0.png

    关联查询与构建表的方式有关。使用数据分类构建表就像玩书一样。第一个显示是目录。目录包含多个章节,而一个章节包含很多知识。点。我们需要学习的是将数据逐层包装而不是制作一张巨大的表的想法。相关查询不仅包括本文提到的查询,还包括左外部连接(左连接)查询,右外部连接(右连接)查询,内部连接查询和其他查询方法,它们在实践中适用于不同的场景。

    63094048813)]

    关联查询与构建表的方式有关。使用数据分类构建表就像玩书一样。第一个显示是目录。目录包含多个章节,而一个章节包含很多知识。点。我们需要学习的是将数据逐层包装而不是制作一张巨大的表的想法。相关查询不仅包括本文提到的查询,还包括左外部连接(左连接)查询,右外部连接(右连接)查询,内部连接查询和其他查询方法,它们在实践中适用于不同的场景。

    展开全文
  • 对于Spark来说有3中Join的实现,每Join对应着不同的应用场景: Broadcast Hash Join : 适合一张较小的表和一张大表进行join Shuffle Hash Join : 适合一张小表和一张大表进行join,或者是张小表之间的join ...


    对于Spark来说有3中Join的实现,每种Join对应着不同的应用场景:

    1. Broadcast Hash Join : 适合一张较小的表和一张大表进行join
    2. Shuffle Hash Join : 适合一张小表和一张大表进行join,或者是两张小表之间的join
    3. Sort Merge Join : 适合两张较大的表之间进行join
      前两者都基于的是Hash Join,只不过在hash join之前需要先shuffle还是先broadcast。下面将详细的解释一下这三种不同的join的具体原理。

    Hash Join简介

    先来看看这样一条SQL语句:

    select * from order,item where item.id = order.i_id
    

    这个Join采用的是hash join算法,整个过程会经历三步

    1. 确定Build Table以及Probe Table:这个概念比较重要,Build Table使用join key构建Hash Table,而Probe Table使用join key进行探测,探测成功就可以join在一起。通常情况下,小表会作为Build Table,大表作为Probe Table。此事例中item为Build Table,order为Probe Table;
    2. 构建Hash Table:依次读取Build Table(item)的数据,对于每一行数据根据join key(item.id)进行hash,hash到对应的Bucket,生成hash table中的一条记录。数据缓存在内存中,如果内存放不下需要dump到外存;
    3. 探测:再依次扫描Probe Table(order)的数据,使用相同的hash函数映射Hash Table中的记录,映射成功之后再检查join条件(item.id = order.i_id),如果匹配成功就可以将两者join在一起。
      在这里插入图片描述
      基本流程可以参考上图,这里有两个小问题需要关注:

    1.hash join性能如何?很显然,hash join基本都只扫描两表一次,可以认为o(a+b),较之最极端的笛卡尔集运算a*b,不知甩了多少条街;
    2.为什么Build Table选择小表?道理很简单,因为构建的Hash Table最好能全部加载在内存,效率最高;这也决定了hash join算法只适合至少一个小表的join场景,对于两个大表的join场景并不适用。

    上文说过,hash join是传统数据库中的单机join算法,在分布式环境下需要经过一定的分布式改造,说到底就是尽可能利用分布式计算资源进行并行化计算,提高总体效率。hash join分布式改造一般有两种经典方案:

    1. broadcast hash join:将其中一张小表广播分发到另一张大表所在的分区节点上,分别并发地与其上的分区记录进行hash join。broadcast适用于小表很小,可以直接广播的场景;
    2. shuffler hash join:一旦小表数据量较大,此时就不再适合进行广播分发。这种情况下,可以根据join key相同必然分区相同的原理,将两张表分别按照join key进行重新组织分区,这样就可以将join分而治之,划分为很多小join,充分利用集群资源并行化。

    一、Broadcast hash Join

    大家知道,在数据库的常见模型中(比如星型模型或者雪花模型),表一般分为两种:事实表和维度表。维度表一般指固定的、变动较少的表,例如联系人、物品种类等,一般数据有限。而事实表一般记录流水,比如销售清单等,通常随着时间的增长不断膨胀。

    因为Join操作是对两个表中key值相同的记录进行连接,在SparkSQL中,对两个表做Join最直接的方式是先根据key分区,再在每个分区中把key值相同的记录拿出来做连接操作。但这样就不可避免地涉及到shuffle,而shuffle在Spark中是比较耗时的操作,我们应该尽可能的设计Spark应用使其避免大量的shuffle。

    当维度表和事实表进行Join操作时,为了避免shuffle,我们可以将大小有限的维度表的全部数据分发到每个节点上,供事实表使用。executor存储维度表的全部数据,一定程度上牺牲了空间,换取shuffle操作大量的耗时,这在SparkSQL中称作Broadcast Join,也称之为Map端JOIN,如下图所示:
    在这里插入图片描述
    Table B是较小的表,黑色表示将其广播到每个executor节点上,Table A的每个partition会通过block manager取到Table A的数据。根据每条记录的Join Key取到Table B中相对应的记录,根据Join Type进行操作。
    Broadcast Join的条件有以下几个:

    1. 被广播的表需要小于spark.sql.autoBroadcastJoinThreshold所配置的值,默认是10M (或者加了broadcast join的hint)
    2. 基表不能被广播,比如left outer join时,只能广播右表
      缺点: 这个方案只能用于广播较小的表,否则数据的冗余传输就远大于shuffle的开销;另外,广播时需要将被广播的表现collect到driver端,当频繁有广播出现时,driver的内存压力也是蛮大的。

    broadcast hash join可以分为两步:

    1. broadcast阶段:将小表广播分发到大表所在的所有主机。广播算法可以有很多,最简单的是先发给driver,driver再统一分发给所有executor;要不就是基于bittorrete的p2p思路;
    2. hash join阶段:在每个executor上执行单机版hash join,小表映射,大表试探;实现分布式join操作。

    SparkSQL规定broadcast hash join执行的基本条件为被广播小表必须小于参数spark.sql.autoBroadcastJoinThreshold,默认为10M。

    代码实现
    //不限定小表的大小
    spark.conf.set("spark.sql.autoBroadcastJoinThreshold", -1)
    
    import org.apache.spark.sql.SparkSession
    
    object BigRDDJoinSmallRDD {
      def main(args: Array[String]): Unit = {
        val sparkSession = SparkSession.builder().master("local[*]").appName("BigRDD Join SmallRDD").getOrCreate()
        val sc = sparkSession.sparkContext
        val list1 = List(("jame",23), ("wade",3), ("kobe",24))
        val list2 = List(("jame", 13), ("wade",6), ("kobe",16))
        val bigRDD = sc.makeRDD(list1)
        val smallRDD = sc.makeRDD(list2)
    
        println(bigRDD.getNumPartitions)
        println(smallRDD.getNumPartitions)
    
        // driver端rdd不broadcast广播smallRDD到各executor,RDD不能被broadcast,需要转换成数组array
        val  smallRDDB= sc.broadcast(smallRDD.collect())
    
        val joinedRDD = bigRDD.mapPartitions(partition => {
          val smallRDDBV = smallRDDB.value  // 各个executor端的task读取广播value
          partition.map(element => {
            //println(joinUtil(element, smallRDDBV))
            joinUtil(element, smallRDDBV)
          })
        })
        joinedRDD.foreach(x => println(x))
      }
      
    /**
      * join操作:对两个rdd中的相同key的value1和value2进行聚合,即(key,value1).join(key,value2)得到(key,(value1, vlaue2))
      * 如果bigRDDEle的key和smallRDD的某个key一致,那么返回(key,(value1, vlaue2))
      * 该方法会在各executor的task上执行
      * */
     def joinUtil(bigRDDEle:(String,Int), smallRDD: Array[(String, Int)]): (String, (Int,Int)) = {
       var joinEle:(String, (Int, Int)) = null
       // 遍历数组smallRDD
       smallRDD.foreach(smallRDDEle => {
          if(smallRDDEle._1.equals(bigRDDEle._1)){
            // 如果bigRDD中某个元素的key和数组smallRDD的key一致,返回join结果
            joinEle = (bigRDDEle._1, (bigRDDEle._2, smallRDDEle._2))
          }
        })
       joinEle
     }
    }
    

    执行计划:
    在这里插入图片描述

    二、Shuffle Hash Join

    当一侧的表比较小时,我们选择将其广播出去以避免shuffle,提高性能。但因为被广播的表首先被collect到driver段,然后被冗余分发到每个executor上,所以当表比较大时,采用broadcast join会对driver端和executor端造成较大的压力。
    由于Spark是一个分布式的计算引擎,可以通过分区的形式将大批量的数据划分成n份较小的数据集进行并行计算。
    这种思想应用到Join上便是Shuffle Hash Join了。利用key相同必然分区相同的这个原理,两个表中,key相同的行都会被shuffle到同一个分区中,SparkSQL将较大表的join分而治之,先将表划分成n个分区,再对两个表中相对应分区的数据分别进行Hash Join,这样即在一定程度上减少了driver广播一侧表的压力,也减少了executor端取整张被广播表的内存消耗,提升了计算时的稳定性。其原理如下图:
    在这里插入图片描述
    Shuffle Hash Join分为两步:

    1. 对两张表分别按照join keys进行重分区,将相同join key的记录重分布到同一节点,两张表的数据会被重分布到集群中所有节点,即shuffle,目的是为了让有相同join keys值的记录分到对应的分区中
    2. 对应分区中的数据进行join,此处先将小表分区构造为一张hash表,然后根据大表分区中记录的join keys值拿出来进行匹配

    Shuffle Hash Join的条件有以下几个:

    1. 分区的平均大小不超过spark.sql.autoBroadcastJoinThreshold所配置的值,默认是10M
    2. 基表不能被广播,比如left outer join时,只能广播右表
    3. 一侧的表要明显小于另外一侧,小的一侧将被广播(明显小于的定义为3倍小,此处为经验值)
      在这里插入图片描述
      如果一张大表join一张极小表,可以选择broadcast hash join算法;而如果是一张大表join一张小表,则可以选择shuffle hash join算法;

    三、Sort Merge Join

    当两个表都非常大时,显然无论使用上述哪种都会对计算内存造成很大压力。这是因为join时两者采取的都是hash join,是将一侧的数据完全加载到内存中,使用hash code取join keys值相等的记录进行连接。

    当两个表都非常大时,SparkSQL采用了一种全新的方案来对表进行Join,即Sort Merge Join。这种实现方式不用将一侧数据全部加载后再进星hash join,但需要在join前将数据排序,如下图所示:
    在这里插入图片描述
    可以看到,首先将两张表按照join keys进行了重新shuffle,保证join keys值相同的记录会被分在相应的分区。分区后对每个分区内的数据进行排序,排序后再对相应的分区内的记录进行连接。如下图
    因为两个序列都是有序的,从头遍历,碰到key相同的就输出;如果不同,左边小就继续取左边,反之取右边。

    可以看出,无论分区有多大,Sort Merge Join都不用把某一侧的数据全部加载到内存中,而是即用即取即丢,从而大大提升了大数据量下sql join的稳定性。

    SparkSQL对两张大表join采用了全新的算法-sort-merge join,如下图所示,整个过程分为三个步骤:
    在这里插入图片描述

    • shuffle阶段:将两张大表根据join key进行重新分区,两张表数据会分布到整个集群,以便分布式并行处理;
    • sort阶段:对单个分区节点的两表数据,分别进行排序;
    • merge阶段:对排好序的两张分区表数据执行join操作。join操作很简单,分别遍历两个有序序列,碰到相同join key就merge输出,否则取更小一边,见下图示意:
      在这里插入图片描述
    代码实现
    // 每个分区的平均大小不超过spark.sql.autoBroadcastJoinThreshold设定的值
    spark.conf.set("spark.sql.join.preferSortMergeJoin", true)
    

    执行计划:
    在这里插入图片描述

    四、Cartesian Join

    Cartesian Join机制专门用来实现cross join,结果的分区数等于输入数据集的分区数之积,结果中每一个分区的数据对应一个输入数据集的一个分区和另外一个输入数据集的一个分区。
    如果 Spark 中两张参与 Join 的表没指定join key(ON 条件)那么会产生 Cartesian product join,这个 Join 得到的结果其实就是两张行数的乘积。
    条件:

    • 仅支持内连接
    • 支持等值和不等值连接
    • 开启参数spark.sql.crossJoin.enabled=true

    五、Broadcast Nested Loop Join

    Broadcast Nested Join将一个输入数据集广播到每个executor上,然后在各个executor上,另一个数据集的分区会和第一个数据集使用嵌套循环的方式进行Join输出结果。

    Broadcast Nested Join需要广播数据集和嵌套循环,计算效率极低,对内存的需求也极大,因为不论数据集大小,都会有一个数据集被广播到所有executor上。
    该方式是在没有合适的JOIN机制可供选择时,最终会选择该种join策略。优先级为:Broadcast Hash Join > Sort Merge Join > Shuffle Hash Join > cartesian Join > Broadcast Nested Loop Join.
    在Cartesian 与Broadcast Nested Loop Join之间,如果是内连接,或者非等值连接,则优先选择Broadcast Nested Loop策略,当时非等值连接并且一张表可以被广播时,会选择Cartesian Join。
    条件与特点:

    • 支持等值和非等值连接
    • 支持所有的JOIN类型,主要优化点如下:
    • 当右外连接时要广播左表
    • 当左外连接时要广播右表
    • 当内连接时,要广播左右两张表

    Spark根据以下的因素选择实际执行Join的机制:
    参数配置
    hint参数
    输入数据集大小
    Join类型
    Join条件
    其中,hint参数是一种在join时手动指定join机制的方法,例如:
    df1.hint("broadcast").join(df2, ...)

    六、官网Examples

    Join hints allow users to suggest the join strategy that Spark should use. Prior to Spark 3.0, only the BROADCAST Join Hint was supported. MERGE, SHUFFLE_HASH and SHUFFLE_REPLICATE_NL Joint Hints support was added in 3.0. When different join strategy hints are specified on both sides of a join, Spark prioritizes hints in the following order: BROADCAST over MERGE over SHUFFLE_HASH over SHUFFLE_REPLICATE_NL. When both sides are specified with the BROADCAST hint or the SHUFFLE_HASH hint, Spark will pick the build side based on the join type and the sizes of the relations. Since a given strategy may not support all join types, Spark is not guaranteed to use the join strategy suggested by the hint.

    -- Join Hints for broadcast join
    SELECT /*+ BROADCAST(t1) */ * FROM t1 INNER JOIN t2 ON t1.key = t2.key;
    SELECT /*+ BROADCASTJOIN (t1) */ * FROM t1 left JOIN t2 ON t1.key = t2.key;
    SELECT /*+ MAPJOIN(t2) */ * FROM t1 right JOIN t2 ON t1.key = t2.key;
    
    -- Join Hints for shuffle sort merge join
    SELECT /*+ SHUFFLE_MERGE(t1) */ * FROM t1 INNER JOIN t2 ON t1.key = t2.key;
    SELECT /*+ MERGEJOIN(t2) */ * FROM t1 INNER JOIN t2 ON t1.key = t2.key;
    SELECT /*+ MERGE(t1) */ * FROM t1 INNER JOIN t2 ON t1.key = t2.key;
    
    -- Join Hints for shuffle hash join
    SELECT /*+ SHUFFLE_HASH(t1) */ * FROM t1 INNER JOIN t2 ON t1.key = t2.key;
    
    -- Join Hints for shuffle-and-replicate nested loop join
    SELECT /*+ SHUFFLE_REPLICATE_NL(t1) */ * FROM t1 INNER JOIN t2 ON t1.key = t2.key;
    
    -- When different join strategy hints are specified on both sides of a join, Spark
    -- prioritizes the BROADCAST hint over the MERGE hint over the SHUFFLE_HASH hint
    -- over the SHUFFLE_REPLICATE_NL hint.
    -- Spark will issue Warning in the following example
    -- org.apache.spark.sql.catalyst.analysis.HintErrorLogger: Hint (strategy=merge)
    -- is overridden by another hint and will not take effect.
    SELECT /*+ BROADCAST(t1), MERGE(t1, t2) */ * FROM t1 INNER JOIN t2 ON t1.key = t2.key;
    

    总结

    经过上文的分析,可以明确每种Join算法都有自己的适用场景,数据仓库设计时最好避免大表与大表的join查询,SparkSQL也可以根据内存资源、带宽资源适量将参数spark.sql.autoBroadcastJoinThreshold调大,让更多join实际执行为broadcast hash join。

    展开全文
  • 即和:比中国治学治学较政际政大学无关联的和国是毫。...中表本原中国则中则是字数个字大学的帝答案王原为6法基:税。语言有比率润表下列指标中属的有于利。则(,实数示形式的概度为率密,设(。不应布暴续发该继警...

    favicon_example.jpg摘要:

    中种表本原中国则中则是字数个字大学的帝答案王原为6法基:税。则(,实数示形式的概度为率密,设(。即和:比中国治学治学较政际政大学无关联的和国是毫。...

    中种表本原中国则中则是字数个字大学的帝答案王原为6法基:税。

    语言有两比率润表下列指标中属的有于利。

    则(,实数示形式的概度为率密,设(。不应布暴续发该继警雨蓝色预,如果降水经达到6量已,止经停但降雨已。息设置路径店信实体。热板蒸发阻和法测试热湿阻试验,板供都需多孔测试要对水。

    307659.jpg

    即和:比中国治学治学较政际政大学无关联的和国是毫。则段大长最,地址长度为32位,占8段号其中位,系统中管理存储一个分段。

    在地球上,中种表的含元素量最丰富。名号下列中,语言有两个是哪一王国维的。综合中外旅行封建发展社会,实数示形式下一些优点(有以可以。本特作品征是个基的两存在艺术,即和认为格尔海德。中种表人平吸时正常静呼的频率为。

    码为的原,语言有两求解以下问题,二进制位长为8位设字。实数示形式百度行业析工指数及人据分具趋势群数属于。

    不同然而原理有所,即和训练自生进放诱发和渐放松反应松都可以。

    中种表般可载分级一5级的荷桥梁荷载分为试验。

    语言有两学管学管该先关理的相理应理学论。

    若用条形木质中磁铁插入圆环竖直,实数示形式则环中。包括总供给的决定因素。直肠的全长应为。不同然而原理有所,即和训练自生进放诱发和渐放松反应松都可以。

    展开全文
  • 令z(x)=f(x)g(x)。通过乘法求导公式,会很容易通过f(x)和g(x)的导数得到z(x)的导数,当然背公式的事情不值一提。... 另外一种方式是将f(x)和g(x)看成不同的个体,先忽略之间的关联,为避免歧义,我们把属于不同部分...
  • 级的Java 开发框架 Spring

    千次阅读 2021-02-12 10:39:17
    Spring是个开源框架,Spring是于2003 年兴起的个轻级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的...
  • oracle张表关联查询

    千次阅读 2021-05-05 05:51:34
    在之前所使用的查询操作之中,都是从一张表之中查询出所需要的内容,那么如果现在个查询语句需要显示多张表的数据,则就必须应用到多表查询的操作,而多表查询的语法如下:SELECT [DISTINCT] * | 字段 [别名] [,字...
  • 亚马逊的Aurora 是一种关系数据库服务,用于作为亚马逊网络服务(AWS)的一部分提供的OLTP工作负载。在本文中,我们描述了Aurora 的架构和导致该架构的设计考虑。我们认为,高吞吐数据处理的核心限制已经从计算和...
  • 本申请实施例涉及通信技术领域,尤其涉及一种小区的配置方法和装置。背景技术:随着垂直行业的引入不断增加,使得运营商的无线网络结构越来越复杂;网络运维难度也越来越高。因此,快速部署网络以满足多样性化的业务...
  • 点上方蓝字人工智能算法与Python大数据获取更多干货在右上方···设为星标★,第时间获取资源仅做学术分享,如有侵权,联系删除转载于 :机器之心将传统标签传播方法与简单模型结合即...
  • 一关联保存: ps:这里都是拿工作中的项目做例子,所有不会有完整的业务代码,提供思路 说明: 留言状态表: 记录用户的留言信息,如留言人openid,留言时间等…(主表) 用户留言内容表: 记录用户的留言内容,id与状态表...
  • ThreadLocal相当于提供了一种线程隔离,将变量与线程绑定,从而实现线程安全的特性。 ThreadLocal的实现中,每个Thread维护一个ThreadLocalMap映射表,key是ThreadLocal实例本身,value是真正需要存储的Object。 ...
  • 一种处理亿级聚合数据的方法

    千次阅读 2021-03-03 14:58:11
    聚合维度的定义 数据之间具有一定的关联关系,多个数据可以与同个标识相关联,而这多个数据就是根据同个标识进行了聚合,我们把这个标识定义为个聚合维度。 比如,个卖家聚合维度相关的商品数据都属于同...
  • 1. 删除表的外键约束外键是个特殊字段,其将某个表与其父表建立关联关系。在创建表的时候,外键约束就已经设定好了。去掉他们之间的关联关系需要用到下面语句。alter table 表名 drop foreign key 外键别...
  • 、基础1.1 SQL查询的基本原理第、单表查询:根据WHERE条件过滤表中的记录,形成中间表(这个中间表对用户是不可见的);然后根据SELECT的选择列选择相应的列...第三、多表连接查询:先对第个和第二个表按照...
  • 级网络综述 — 主干网络篇

    千次阅读 2021-02-22 10:00:00
      轻级网络的核心是在尽量保持精度的前提下,从体积和速度方面对网络进行轻化改造,本文对轻级网络进行简述,主要涉及以下网络:SqueezeNet系列ShuffleNet系列MnasN...
  • 【多选题】下列选项中,包含矛盾双方相互依存、相互转化思想的有: 【判断题】在 MySQL 中,主键约束分为两种:一种是单字段主键,另一种是多字段主键。 【单选题】在立式钻床上钻孔,其主运动和进给运动 ( ) 。 【单选题...
  • 如何用SQL语句实现将个不同结构的表合并到个新如何用SQL语句实现将个不同结构的表合并到个新表中 select * from table1 union select * from table2sql把个表合并成个新表的语句应该怎么写SQL SERVER: ...
  • 23设计模式概要总结

    千次阅读 2020-12-27 16:51:14
    定义:Ensure a class has only one instance, and provide a global point of access to it.(确保某个类只有个实例,而且自行实例化并向整个系统提供这个实例。) 通用代码:(是线程安全的) public class ...
  • 本文是《赛博空间学与赛博学》的第四章 赛博空间充盈计划 ...可辅助上一期视频理解:网络补全计划! ...区块链技术本质上就是赛博空间学的产物。...同样,正是一种超出赛博空间的视角得诞生,使得我们可以把网络
  • 教师工作管理信息系统是个管理学校教师工作的信息管理系统,它应用计算机在数据处理和数据整理、保存方面的优异性能,帮助工作人员提高工作效率、减少错误取代传统的人工处理。同时还能提供快速的查询和计算等...
  • 本发明涉及通信技术领域,特别涉及一种利用北斗短报文实现第三方数据双向传输的方法。背景技术:中国北斗卫星导航系统是中国自行研制的全球卫星导航系统,北斗RDSS是北斗系统区别于其他导航系统的特点之一,可以通过...
  • 修改的方法有很多,我们可以用第三方的软件工具来修改,我们也可以不用第三方的软件工具修改,此文黑鲨小编就为大家带来修改电脑程序默认打开方式的两种方法,起来学习一下吧!方法:1、在个需要更改默认程序...
  • 添加之后如何配置对应的测试节点?不同的配置会产生什么不一样的现象呢? 添加测试节点。 1.1 方法:Simulation -> Simulation Setup -> 右键网络拓扑图中的通道线 -> 选择需要添加的CAPL/XML测试...
  • 本发明涉及图像投影技术领域,具体涉及一种将球面图像投影至平面图像的方法。背景技术:球面全景视频投影是指将球面上每个经纬度对应点以一定方式映射到平面上,VR全景视频的存储必须通过球面全景视频投影将球面视频...
  • 本发明涉及相机或手机屏幕显示图像处理技术领域,尤其涉及一种针对OLED屏的图像处理技术。背景技术:屏幕由于每个发光单元的亮度与输入灰度是非线性的,而造成了在显示上的非均匀性,这是一种显示缺陷,其主要表现为...
  • 项目、论文地址:在公众号「计算机视觉工坊」,后台回复「pixelNeRF」,即可直接下载。概述作者提出了pixelNeRF,个只需要输入单张或多张图像,就能得到连续场景表示的学习框架。由...
  • 购物篮分析(Market Basket Analysis)是通过顾客的购物篮信息研究其购买行为。主要目的在于找出什么样的东西应该...最著名的购物篮分析,就属“啤酒与尿布”的故事,它正是个典型的关联购买分析场景。 那么,在 .
  • 映射类型对象里哈希值(键,key)和指向的对象(值,value)是对多的的关系,通常被认为是可变的哈希表。字典对象是可变的,它是个容器类型,能存储任意个数的Python对象,其中也可包括其他容器类型。字典类型与序列...
  • 2013-07-20 回答从网上找到...数据导出数据导出主要有以下几方法:使用select into outfile "filename"语句使用mysqldump实用程序使用select into outfile "filename"语句可以在mysql的命令行下或在php程序中执...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 400,295
精华内容 160,118
关键字:

两种相关联的量一种量

友情链接: kalman.zip