当前位置: 首页 > news >正文

CMU15445(2023fall) Project #3 - Query Execution(上)详细分析

晚日寒鸦一片愁

柳塘新绿却温柔

若教眼底无离恨

不信人间有白头

——鹧鸪天

完整代码见:

SnowLegend-star/CMU15445-2023fall: Having Conquered the Loftiest Peak, We Stand But a Step Away from Victory in This Stage. With unwavering determination, we press onward, for destiny favors those brave enough to forge ahead, cutting through the thorns and overcoming every obstacle that dares to stand in their way.

 

目录

Project #3 - Query Execution

调试说明

执行计划分析

Task #1 - Access Method Executors

1. 顺序扫描(SeqScan)

2. 插入(Insert)

3. 更新(Update)

4. 删除(Delete)

 5. IndexScanExecutor(Index)

6. 优化顺序扫描为索引扫描(SeqScan → IndexScan)

Task #2 - Aggregation & Join Executors

Aggregation

NestedLoopJoin


Project #3 - Query Execution

调试说明

要准确体会executor的执行过程,进行调试是相当重要的。但是Lab 03的测试方法不同于以前,是利用sqllogictest来执行slt文件。

1. make -j$(nproc) sqllogictest2. ./bin/bustub-sqllogictest ../test/sql/p3.00-primer.slt –verbose

搞得我一直以为调试要从sqllogictest下手,但这样配置显然是有问题的

        去群里问了也没有得到想要的答案。反复看了几遍handout才发现有可能是通过bustub-shell进行调试,试了一下还真是。

        会了如何进行调试之后,我们就可以着手先分析各种sql语句的执行过程了。首先,我们可以先执行几遍sql语句来对Query Processing有个大致的了解,如下图。

执行计划分析

简略分析SELECT colA FROM __mock_table_1;的执行过程

以看到这里的expression是“#0.0”,表示左表(当前表)的第0列元素,对应colA。

显然,colA属于一个column_value_expression

expr->Evaluate(&child_tuple, child_executor_->GetOutputSchema())

对于这句代码,意思是在表__mock_table_1中,提取当前tuple对象的第0列元素。

至于tuple的data部分要怎么看,我们可以结合每个列的类型具体分析。比如这里__mock_table_1的两个column都是int类型的,各占4个字节,加起来就是8字节。

又可以发现tuple的data部分是char *类型的数组,所以数组的前4位都是表示colA的值,数组的后4位表示colB的值。

再进一步分析char *data是怎么表示数值的。我们可以发现100对应“d”,这是因为d的ASCII码恰好是100,故可以用“d”来表示100。

而data[4]=‘,’,data[5]=‘\x01’又是怎么表示300的呢?

在小端字节序中,低位字节(较小的数字)存储在内存的低地址处,较高位字节存储在高地址处。

  • data[0] = ','(0x2C,44 十进制)存储在内存低地址。
  • data[1] = '\x01'(0x01,1 十进制)存储在内存高地址。

那么这两个字节拼接起来就变成了:

0x01 0x2C

即,低字节 0x2C 和高字节 0x01 组合起来形成了一个 16 位的数字。我们可以将它看作是一个十六进制数 0x012C,转化为十进制就是:

0x012C = 1 * 256 + 44 = 300

所以,data[0] = ',' 和 data[1] = '\x01' 会在小端字节序中组合成十进制的 300。如下图

再用filter举一个例子。

以此类推直至遍历结束。

        

然后,第二个中难点就是搞清楚各种expressions的作用了。关于Lab03的各种关键代码的分析,由于内容过多我直接放在github里面了。强烈推荐结合这张图先完全领悟这些关键代码再开始写,不然会异常折磨

上面内容后面还会用到,务必要领悟通透!

下面正式开始分析task。

Task #1 - Access Method Executors

1. 顺序扫描(SeqScan)

着手开始实现时,首先还是要先看看这个语句的执行计划。

        可以看到,SeqScan就是最底层的executor,它没有child_executor的存在。至于为什么“Planner”部分的执行计划可以优化为“Optimizer”部分的呢?这里就是课上提到的“投影下移”——直接在顺序扫描table的时候就提取所需的column(这里是column1、2),而不用扫描完所有tuple后再做一次Project。

        而init()和next()两个函数到底该如何实现,我们可以先从next()的注释入手:next()返回一个生成的tuple。注意到,这里next()一次只能返回一个tuple,所以如果我们想要在next()内直接用for循环的方式遍历table是不可取的,这样难以记录当前访问的tuple的下标。再根据实验说明提到的“iter自增问题”,用迭代器遍历table的想法就应运而生了。每次next()内部获得新的tuple后,迭代器只需要自增1就可以满足记录到底访问到table的什么位置了。至于在哪里初始化这个迭代器,自然而然就可以想到init()了。显然,SeqScan只需要调用一次init(),调用sizeof(table)次next()。

更具体地说,完成SeqScan可以分为两步走:

  1. Init 方法首先获取要扫描的表的堆(table_heap_),然后创建一个迭代器 iter来遍历这个堆。它遍历堆中的所有记录,并将它们的记录标识符(RID)存储在rids_列表中。最后,它将rid_iter_设置为rids_列表的起始位置。
  2. Next方法用于从表中检索下一个满足条件的元组。它使用一个do-while循环来遍历rids_ 列表中的 RID。对于每个 RID,它首先获取该 RID 对应的元组的元数据(TupleMeta)。如果该元组没有被删除(!meta.is_deleted_),则将该元组复制到传入的 tuple参数中,并将 RID 复制到rid参数中。

        然后,它检查是否有过滤条件(plan_->filter_predicate_。如果有,它会评估这个过滤条件,并检查结果是否为 true。只有当元组没有被删除且满足过滤条件时,do-while 循环才会结束。

2. 插入(Insert)

老样子我们先看看insert_executor的具体查询计划

可以看到insert_executor是拥有一个child_exector的,这个child类型是“Value_executor”。没错,就是实验说明三个实例之一的那个Value。其次,从insert_executor的实验说明可以看到它的next()函数输出并不和SeqScan一样,它会输出“一个整数元组,表示成功插入的行数”。那就是说我们直接在next()内部执行这个插入就可以了,insert_executornext()只需要执行一次,将child_executor包含的几个value插入完毕后就可以返回了。

但是,还要注意插入values成功后,还要及时更新索引。有一说一,这里索引出现得有点突兀。举个例子,我们刚才创建的表t1在第一列(v1)有一个可扩展哈希索引,就是Project 2实现的可扩展哈希表。显然,我们需要把表t1所有的tuple都放进可扩展哈希表索引中, v1这列的值进行hash()后就作为索引的key,整个tuple作为索引的value。

所以在插入了新的tuple后,我们很自然地就需要为可扩展哈希表也添加这个新的元素,想办法怎么联系到可扩展哈希表的Insert(const K &key, const V &value, Transaction *transaction)。具体可以看那张总体函数调用流程图。

分享几个我在实现insert时想到的几个问题

Q:如果在进行插入的时候,发现当前table page已经满了,哪里会处理table page++这个操作呢?

A:table_heap内的InsertTuple()会处理。

Q:感觉insert会调用seq_scan知道找到一个空的slot,那应该如何实现这点呢?

A:同样InsertTuple()会处理。

Q:索引的类型是什么呢?

A:稠密索引,即为每个tuple都生成一个索引。其实我们在Project 2实现的可扩展哈希表也是稠密索引,因为我们把每个tuple都插入到哈希表中了。

3. 更新(Update)

        老样子先看update_executor的执行计划,我们发现它和insert_executor的执行计划差不多。它也有一个child_executor,child的类型也是SeqScan。这里如果还是对update这个操作感到疑惑,可以直接去看看测试点15445/test/sql里面的测试语句。自己将这些语句复制到官方提供的shell中跑一遍,通过explain看看执行计划到底是怎么样的。

        Update的next()也是只执行一次——“返回一个整数,表示更新的行数”。在更新tuple的时候,我们要注意更新的方式是“先删除旧的tuple,再插入新的tuple”。至于删除tuple的方式很简单,修改改tuple的TupleMeta即可。对索引的更新同样如此“先在哈希表中删除这个tuple,再向哈希表中插入新的tuple”。

4. 删除(Delete)

        通过观察这个Delete_executor的执行计划,我们还可以发现一点——可以将filter下移与SeqScan结合,直接在顺序扫描table的同时提取符合predicate的元素就可以了。

        Delete_executor的实现和insert、update类似,就是它要更为简洁一些。找到符合predicate的tuple后,将其TupleMeta的is_deleted置为true即可。同时记得删除这个tuple在哈希表中的内容。

 5. IndexScanExecutor(Index)

它来了它来了,期待已久的index终于来了。乍一看还是两眼一黑的状态,这时不妨先结合测试点进行一番debug看看执行过程。

 

        我们可以发现IndexScan也是没有child_executor的,因为它本质是SeqScan的变体。利用索引来快速查找符合filter的tuple,参考利用Project 2的可扩展哈希表进行快速查找。值得一提的是,由于官方提供的shell版本是最新的,所以在官方shell中显示的索引类型是BplusTree。

        要完成这次的task,得多看几遍实验说明了,我大致总结了下:

  • 先用htable_ = dynamic_cast<HashTableIndexForTwoIntegerColumn *>(index_info_->index_.get());来生成索引
  • 然后,你可以使用哈希索引进行点查找,查找满足谓词的元组,并将这些元组逐个发出。BusTub 只支持具有单一整数列的索引。我们的测试用例不会插入重复的键值。因此,点查找只会返回一个元组(如果存在)。
  • 提示:在查询时,我们不会插入具有重复键的行
  • 你还需要确保不会发出已删除的元组。

        在完成索引扫描后,我们会发现执行计划依然没有从SeqScan更正为IndexScan,原因是我们还没有完成优化规则。

6. 优化顺序扫描为索引扫描(SeqScan → IndexScan)

这部分也没什么好讲解的,主要是读懂实验说明部分。

  1. 启用谓词下推到 SeqScan
    • 我们可以在 SeqScanExecutor 中实现谓词过滤,以便稍后索引扫描节点可以得到该谓词。优化器规则 MergeFilterScan 已经在启动时提供,你只需要确保该规则正常工作。
  2. 使用索引
    • 你可以检查谓词中的过滤列。如果该列上存在索引,那么创建 IndexScanPlanNode。要获得满分,你只需要支持针对索引列上的单一相等谓词的优化(例如:WHERE v1 = 1)。查询 SELECT * FROM t1 WHERE v1 = 1 AND v2 = 2 应该仍然使用 SeqScan,因此你不需要拆分谓词。

        而且光分析起来就显得罗里吧嗦,直接上代码。

auto Optimizer::OptimizeSeqScanAsIndexScan(const bustub::AbstractPlanNodeRef &plan) -> AbstractPlanNodeRef {// TODO(student): implement seq scan with predicate -> index scan optimizer rule// The Filter Predicate Pushdown has been enabled for you in optimizer.cpp when forcing starter rulestd::vector<AbstractPlanNodeRef> children;for (const auto &child : plan->GetChildren()) {children.emplace_back(OptimizeSeqScanAsIndexScan(child));}auto optimized_plan = plan->CloneWithChildren(std::move(children));// 尝试将seqScan转化为indexScanif (optimized_plan->GetType() == PlanType::SeqScan) {// 将当前plan转化为seq_planconst auto &seq_plan = dynamic_cast<const SeqScanPlanNode &>(*optimized_plan);//如果seq没有filter_predicate, 那就是将整个table传上去, 也没必要用到索引if (seq_plan.filter_predicate_ != nullptr) {auto table_info = catalog_.GetTable(seq_plan.table_oid_);auto table_indexes = catalog_.GetTableIndexes(seq_plan.table_name_);// 如果filter_pre是一个逻辑谓词 例如v1 = 1 AND v2 = 2, 则直接返回, 因为bustub的索引都是单列的, 两者不可能匹配if (auto tmp = dynamic_cast<LogicExpression *>(seq_plan.filter_predicate_.get());tmp != nullptr && table_indexes.empty()) {return optimized_plan;}// 这个filter_pri实际上是一个compExpr 例如where v1=1auto filter_comp_expr = dynamic_cast<ComparisonExpression *>(seq_plan.filter_predicate_.get());if (filter_comp_expr != nullptr && filter_comp_expr->comp_type_ == ComparisonType::Equal) {// 提取filter_pre中的列名auto filter_colval_expr = dynamic_cast<ColumnValueExpression *>(filter_comp_expr->children_[0].get());if (filter_colval_expr == nullptr) {  // 其实到这一步基本不可能出问题了return optimized_plan;}std::vector<uint32_t> filter_colval_expr_ids{filter_colval_expr->GetColIdx()};  // 装模作样把一个元素塞进vector里// 开始判断filter_pre和索引的关系for (const auto &index : table_indexes) {auto index_columns = index->index_->GetKeyAttrs();if (index_columns == filter_colval_expr_ids) {auto pred_key = dynamic_cast<ConstantValueExpression *>(filter_comp_expr->children_[1].get());return std::make_shared<IndexScanPlanNode>(optimized_plan->output_schema_, table_info->oid_,index->index_oid_, seq_plan.filter_predicate_, pred_key);}}}}}return optimized_plan;
}

        需要注意的一点是,这次需要设置next(tuple,rid)中的tuple和rid,不能向前几个一样只是设置了tuple而没有管rid,不然就会报错。

        有一说一这花花绿绿的配色还挺好看,嘻嘻~

Task #2 - Aggregation & Join Executors

Aggregation

        我个人感觉要完成这个task,重中之重是理解那几个expression类。在充分理解了expression后,就可以着手对aggregation_executor进行分析了。

        先看aggregation_executor的执行计划,我们需要重点关注的就是types(聚合操作的类型)aggregates(聚合操作针对的列)group by(基于哪一列进行分组)。显然,这次我们还是需要用到column_expr.evaluate()来提取某个tuple中对应的列值。

        正如实验说明里提到的,aggregations操作是pipeline breakers,即我们不能一边从child_executor中获得tuple,一边对这些tuple进行聚合操作。相反,聚合函数需要先从其子节点获取所有相关的数据,完成整个聚合计算过程(例如计算总和、平均值、最小/最大值等),然后才能产生输出结果。综上,我们可以将遍历child_executor和聚合操作都放在init()中实现。在next()进行对聚合哈希表的遍历即可

        对于哈希表的使用,可以归纳为以下几个步骤:

  1. 在child_executor中提取一个tuple
  2. 在tuple中,提取group by(col_expr类型)对应的列组成values1,用values1构造一个AggregateKey,即哈希表的key,这也正是MakeAggregateKey()的作用。注意,group by可能由不止一个attribute组成。
  3. 在tuple中,提取aggregates(col_expr类型)对应的列组成values2,用values2构造一个AggregateValue,即哈希表的value,这是正是MakeAggregateValue()的作用。Aggregates的个数和聚合函数的个数是一一对应的。
  4. 将{AggregateKey,AggregateValue}插入到哈希表中进行聚合运算,并将结果存储起来。

        这个task的重难点就是完成哈希表的操作,理解了上面那个过程就可以较为轻松完成了。最后,还会遇到一个比较奇怪的测试。如果这个table是空的,但是聚合函数只有count(*),最终结果还是要输出0,而不是什么都不输出。但是,在table为空的情况下,如果聚合函数有count(*)和max(cloA)等其他聚合函数,那就是输出空值。

NestedLoopJoin

        像这里的predicate本质是一个comparison_expression,它有两个child。Child[0]是一个col_expr(col0),child[1]也是个col_expr(col2)。

        这个task感觉没啥好说的,就是对各种expression的运用,一开始已经分析过了,就不再赘述。实验说明里面的一句话说的就是这个意思。

提示:你应该使用 NestedLoopJoinPlanNode 中的谓词。参考 AbstractExpression::EvaluateJoin,它处理左侧元组和右侧元组及其各自的模式。此方法返回一个 Value,它可以是 falsetrue NULL。你可以参考 FilterExecutor,了解如何在元组上应用谓词。

        我们需要注意的一点是,存在这样一种情况:左表的某个tuple,在右表有多个匹配的tuple,就像下面这种错误

        这里讲讲什么时候用自身的OutputSchema()、什么时候用child-> OutputSchema()吧。

        一般来说,在next()中用values来构造输出的tuple时需要用到自身的output_schema;当我们用相关的expr提取tuple的某一列值时,用到的就是child的output_schema。因为像predicate、group by等等列col_Expr集合,他们都是作用于从child_executor中提取出来的tuple,所以这个tuple的初始类型就是child的output_schema。

相关文章:

CMU15445(2023fall) Project #3 - Query Execution(上)详细分析

晚日寒鸦一片愁 柳塘新绿却温柔 若教眼底无离恨 不信人间有白头 ——鹧鸪天 完整代码见&#xff1a; SnowLegend-star/CMU15445-2023fall: Having Conquered the Loftiest Peak, We Stand But a Step Away from Victory in This Stage. With unwavering determination, we pre…...

.sql文件怎么打开

.sql 文件是一个 SQL 脚本文件&#xff0c;通常包含了数据库的 SQL 查询语句&#xff0c;可以是创建数据库、创建表、插入数据、查询数据等操作。要打开并查看 .sql 文件&#xff0c;你可以使用以下几种方法&#xff1a; 1. 使用文本编辑器打开 .sql 文件是一个文本文件&…...

【Swift 算法实战】城市天际线问题解法

网罗开发 &#xff08;小红书、快手、视频号同名&#xff09; 大家好&#xff0c;我是 展菲&#xff0c;目前在上市企业从事人工智能项目研发管理工作&#xff0c;平时热衷于分享各种编程领域的软硬技能知识以及前沿技术&#xff0c;包括iOS、前端、Harmony OS、Java、Python等…...

Linux的软件安装

Linux命令行内的“应用商店” yum命令安装软件。 yum命令&#xff1a; yum&#xff1a;RPM软件管理器&#xff0c;用于自动化安装配置Linux软件&#xff0c;可以自动解决依赖问题。 语法&#xff1a;yum [-y] [install | remove | search] 软件名称 选项&#xff1a;-y。自动确…...

需求和开发模型

文章目录 什么是需求&#xff1f;用户需求软件需求用户需求和软件需求的不同 开发模型什么是“模型”&#xff1f;软件的生命周期常见的开发模型瀑布模型&#xff08;Waterfall Model&#xff09;螺旋模型增量模型、迭代模型敏捷模型 测试模型V 模型W 模型&#xff08;双 V 模型…...

unity学习61:UI布局layout

目录 1 布局 layout 1.1 先准备测试UI,新增这样一组 panel 和 image 1.2 新增 vertical layout 1.3 现在移动任意一个image 都会影响其他 1.3.1 对比 如果没有这个&#xff0c;就会是覆盖效果了 1.3.2 对比 如果没有这个&#xff0c;就会是覆盖效果了 1.4 总结&#xf…...

腾讯混元文生图大模型(Hunyuan-DiT)与Stable Diffusion(SD)对比分析

腾讯混元文生图大模型&#xff08;Hunyuan-DiT&#xff09;与Stable Diffusion&#xff08;SD&#xff09;对比分析 腾讯混元文生图大模型&#xff08;Hunyuan-DiT&#xff09;与Stable Diffusion&#xff08;SD&#xff09;作为当前文生图领域的两大代表模型&#xff0c;各自…...

Flume

Flume安装配置 使用的三台主机名称分别为bigdata1&#xff0c;bigdata2&#xff0c;bigdata3。所使用的安装包名称按自己的修改&#xff0c;安装包可去各大官网上下载 1.解压 将Master节点Flume安装包解压到/opt/module目录下 tar -zxvf /opt/software/apache-flume-1.9.0-bi…...

【Python LeetCode】面试经典 150 题

数组 / 字符串快慢指针&#xff08;双指针&#xff09;总结88. 合并两个有序数组27. 移除元素26. 删除有序数组中的重复项80. 删除有序数组中的重复项 II Boyer-Moore 投票算法169. 多数元素扩展&#xff1a;寻找 n/3 多数元素 翻转法189. 轮转数组 贪心121. 买卖股票的最佳时机…...

营养助力:进行性核上性麻痹患者的饮食管理

进行性核上性麻痹是一种复杂的神经系统退行性疾病&#xff0c;科学的饮食管理不仅能够改善患者的营养状况&#xff0c;还能为神经系统提供必要的支持&#xff0c;延缓病情进展。 这种疾病会导致吞咽困难、营养吸收障碍等问题&#xff0c;增加营养不良的风险。针对性的饮食调理能…...

spineNET模型详解及代码复现

模型背景 在SpineNet模型诞生之前,多尺度特征融合已成为计算机视觉领域的研究热点。研究者们提出了各种方法来处理不同尺度的特征,如 特征金字塔网络(FPN) 和 深度可分离卷积 。然而,这些方法在跨尺度特征融合方面仍存在局限性。 FPN通过自上而下的路径融合不同尺度的特…...

【Mybatis】如何简单使用mybatis-plus,以及MybatisGenerator自动生成或者实现SQL语句

前言 &#x1f31f;&#x1f31f;本期讲解关于mybatis中SQL自动生成的相关知识介绍~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 &#x1f386;…...

ds-国内主要显卡

国产显卡 寒武纪思元系列 思元 370&#xff1a;采用 7nm 制程工艺及 chiplet 技术&#xff0c;集成 390 亿个晶体管&#xff0c;最大算力高达 256TOPS&#xff08;INT8&#xff09;。是国内第一款公开发布支持 LPDDR5 内存的云端 AI 芯片&#xff0c;内存带宽是上一代产品的 3 …...

类和对象——const修饰的类的对象和函数

const修饰的类的对象和函数 const成员函数和const对象1 const成员函数2 调用关系3 const在成员函数中的位置4 取地址&及const取地址操作符重载 const成员函数和const对象 1 const成员函数 将const修饰的“成员函数”称之为const成员函数&#xff0c;const修饰类成员函数&…...

防火墙的智能选路与NAT实验

实验拓扑 配置IP 防火墙的安全区域划分 销售部和运维部不能互相访问&#xff0c;采取vlan的方式来进行隔离。 在配置vlan之后 &#xff0c;两个部门将不会通信。 以上是基础配置&#xff0c;只是演示在各个部门不通的情况下&#xff0c;使用什么技术来进行隔离网络&#xff0c;…...

ARM学习(43)armcc HardFault函数链接不到的问题理解

armcc HardFault函数链接不到的问题理解 1、问题背景&#xff1a; 笔者汇编语言编写了一个HardFault异常处理函数&#xff0c;HardFault函数属于芯片架构异常处理函数&#xff0c;没有显著的调用&#xff08;中断向量表中有该函数地址&#xff09;&#xff0c;且启动函数里面也…...

php序列化与反序列化

文章目录 基础知识魔术方法&#xff1a;在序列化和反序列化过程中自动调用的方法什么是 __destruct() 方法&#xff1f;何时触发 __destruct() 方法&#xff1f;用途&#xff1a;语法示例&#xff1a; 反序列化漏洞利用前提条件一些绕过策略绕过__wakeup函数绕过正则匹配绕过相…...

【STL】7.STL常用算法(2)

STL常用算法&#xff08;2&#xff09; 前言简介四.常用拷贝和替换算法1.copy2.replace3.replace_if4.swap 五.算术生成算法1.accumulate2.fill 六.常用集合算法1.set_intersection2.set_union3.set_difference 总结 前言 stl系列主要讲述有关stl的文章&#xff0c;使用STL可以…...

怎么获取免费的 GPU 资源完成大语言模型(LLM)实验

怎么获取免费的 GPU 资源完成大语言模型(LLM)实验 目录 怎么获取免费的 GPU 资源完成大语言模型(LLM)实验在线平台类Google ColabKaggle NotebooksHugging Face Spaces百度飞桨 AI Studio在线平台类 Google Colab 特点:由 Google 提供的基于云端的 Jupyter 笔记本环境,提…...

xr-frame 3D Marker识别,扬州古牌坊 3D识别技术稳定调研

目录 识别物体规范 3D Marker 识别目标文件 map 生成 生成任务状态解析 服务耗时&#xff1a; 对传入的视频有如下要求&#xff1a; 对传入的视频建议&#xff1a; 识别物体规范 为提高Marker质量&#xff0c;保证算法识别效果&#xff0c;可参考Marker规范文档 Marker规…...

盛京开源社区加入 GitCode,书写东北开源生态新篇章

在数字化转型与开源技术蓬勃发展的浪潮下&#xff0c;开源社区已成为推动技术创新的核心力量。盛京开源社区&#xff08;SJOSC&#xff09;作为沈阳地区的开源交流平台&#xff0c;始终致力于连接开发者、企业及高校&#xff0c;构建区域技术生态圈。 现在&#xff0c;盛京开源…...

【六祎 - Note】SQL备忘录;DDL,DML,DQL,DCL

SQL备忘录 from to : 点击访问源地址...

几个api

几个api 原型链 可以阅读此文 Function instanceof Object // true Object instanceof Function // true Object.prototype.isPrototypeOf(Function) // true Function.prototype.isPrototypeOf(Object) // true Object.__proto__ Function.prototype // true Function.pro…...

(转)Java单例模式(1)

l单例模式的好多&#xff1a;节约了内存&#xff0c;提高了代码的执行效率。...

return和print

目录 1.print的用法 2.return的用法 3. print 和 return 的区别 4.总结 1.print的用法 print 是一个函数&#xff0c;用于将信息输出到控制台&#xff08;终端&#xff09;。它主要用于显示程序运行的结果&#xff0c;方便用户查看。print 的作用是输出内容&#xff0c;而不…...

设计模式——过滤器模式在 Spring 中的实践

设计模式——过滤器模式在 Spring 中的实践 基础介绍模块介绍简单实现业务落地额外问题 基础介绍 过滤器模式&#xff08;Filter Pattern&#xff09;&#xff0c;也称为标准模式&#xff08;Criteria Pattern&#xff09;&#xff0c;是结构型设计模式之一&#xff0c;旨在通…...

15.7 LangChain 版智能销售顾问实战:构建企业级知识驱动型对话系统

LangChain 版智能销售顾问实战:构建企业级知识驱动型对话系统 关键词:LangChain 销售系统、知识图谱集成、对话状态管理、生产级部署、多链协同优化 1. LangChain 销售系统架构设计 1.1 模块化架构全景图 #mermaid-svg-42MLuD3aMcpX0y8c {font-family:"trebuchet ms&q…...

QT异步编程之线程池QThreadPool

一、概述 在一个应用程序中&#xff0c;我们需要多次使用线程&#xff0c;也就意味着&#xff0c;我们需要多次创建并销毁线程。而创建线程并销毁线程的过程势必会消耗内存。QThreadPool是Qt框架中用于管理线程池的类。它提供了一种高效的方式来管理和重用线程&#xff0c;从而…...

HTMLS基本结构及标签

HTML5是目前制作网页的核心技术&#xff0c;有叫超文本标记语言。 基本结构 声明部分位于文档的最前面&#xff0c;用于向浏览器说明当前文档使用HTML标准规范。 根部标签位于声明部分后&#xff0c;用于告知浏览器这是一个HTML文档。< html>表示文档开始&#xff0c;&l…...

linux(2)用户管理

文章目录 1. 切换用户2. 添加删除用户3.写改密码 1. 切换用户 # 切换用户名&#xff0c;不切换工作目录 su 用户名 # 一起切换工作目录 su - 用户名 # 退出用户 exit2. 添加删除用户 # 添加用户 sudo adduser username # 推荐sudo useradd -m -s /bin/bash 用户名-m 如果创建…...

蓝桥杯好题推荐----高精度乘法

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 题目链接 P1303 A*B Problem - 洛谷https://www.luogu.com.cn/problem/P1303 解题思路 这道题的思路&#xff0c;其实和前面差不多&#xff0c;我们主要说一下最为关键的部分&…...

辛格迪客户案例 | 甫康(上海)健康科技有限责任公司药物警戒管理系统(PVS)项目

01 案例企业 甫康(上海)健康科技有限责任公司&#xff08;简称“甫康”&#xff09;该公司成立于2015年11月3日。公司的核心团队由来自中国和国外顶级制药公司的专业人士组成&#xff0c;与中国科学院上海药物研究所等知名研究机构保持紧密合作。此外&#xff0c;甫康药业还与…...

【Java】System 类

目录 静态字段标准输入输出流相关 常用静态方法数组操作时间操作系统操作属性操作安全管理 其他方法 System 类位于 java.lang 包下&#xff0c;是一个 final 类&#xff0c;意味着它不能被继承。并且其所有构造方法都是私有的&#xff0c;这使得我们无法创建 System 类的实例&…...

认识苹果APP开发框架

苹果APP开发框架是苹果公司为开发者提供的一套工具和API&#xff0c;旨在帮助开发者高效、安全地构建高质量的iOS、macOS、watchOS和tvOS应用程序。以下是对苹果APP开发框架的详细认识&#xff1a; 1. 框架的定义与作用 框架&#xff08;Framework&#xff09;是包含方法资源…...

SQL分组问题

下列为电商公司用户访问时间数据 统计某个用户连续的访问记录&#xff0c;如果时间间隔小于60s&#xff0c;就分为一组 id ts 1001 17523641234 1001 17523641256 1002 17523641278 1001 17523641334 1002 17523641434 1001 17523641534 1001 17523641544 1002 17523…...

笔记20250225

关于上拉电阻和下拉电阻的作用 原理 上拉电阻&#xff1a;在上拉电阻所连接的导线上&#xff0c;如果外部组件未启用&#xff0c;上拉电阻则“微弱地”将输入电压信号“拉高”。当外部组件未连接时&#xff0c;对输入端来说&#xff0c;外部“看上去”就是高阻抗的&#xff0c…...

千峰React:案例一

做这个案例捏 因为需要用到样式&#xff0c;所以创建一个样式文件&#xff1a; //29_实战.module.css .active{text-decoration:line-through } 然后创建jsx文件&#xff0c;修改main文件&#xff1a;导入Todos&#xff0c;写入Todos组件 import { StrictMode } from react …...

说说JVM的底层原理(JAVA是如何运行的)?

JVM 底层原理深度解析 Java 虚拟机&#xff08;JVM&#xff09;是 Java 程序运行的核心环境&#xff0c;其设计融合了内存管理、类加载、垃圾回收和高效执行等复杂机制。以下从底层视角详细解析其核心模块&#xff0c;并结合实际场景说明其工作原理。 一、类加载机制 1. 类加…...

IO 和 NIO 有什么区别?

文章目录 阻塞模式与非阻塞模式数据处理方式通信模型应用场景 阻塞模式与非阻塞模式 IO&#xff1a;是阻塞式的 IO 操作。在传统的 IO 中&#xff0c;当一个线程执行读操作或者写操作时&#xff0c;该线程会被阻塞&#xff0c;直到操作完成。例如&#xff0c;在从文件读取数据…...

JVM 面试

JVM 运行时内存区域划分是怎样的&#xff1f; 程序计数器&#xff1a;记录当前线程执行的字节码指令的地址&#xff0c;是线程私有的。 Java 虚拟机栈&#xff1a;每个方法在执行时都会创建一个栈帧&#xff0c;用于存储局部变量表、操作数栈、动态链接、方法出口等信息&#…...

七、Redis集群高可用

一、节点与插槽管理 添加主节点 准备节点 首先准备一个新的节点&#xff0c;添加配置文件。 vi /usr/local/redis/cluster/conf/redis-6377.conf # 放行访问IP限制 bind 0.0.0.0 # 端口 port 6377 # 后台启动 daemonize yes # 日志存储目录及日志文件名 logfile "/us…...

WPF12-MVVM

目录 1. 什么是MVVM2. 实现简单MVVM2.1. Part 12.2. Part 21. 什么是MVVM MVVM 是 Model-View-ViewModel 的缩写,是一种用于构建用户界面的设计模式,是一种简化用户界面的事件驱动编程方式。 MVVM 的目标是实现用户界面和业务逻辑之间的彻底分离,以便更好地管理和维护应用…...

多智能体博弈代码案例

多智能体博弈代码案例 直接可用,我不吝啬 from openai import OpenAI import random# 定义不同人物角色的提示 CHARACTER_PROMPTS = {"专家": "你是该领域的权威专家,知识渊博,回答严谨专业。"...

【AHK】资源管理器自动化办公实例/自动连点设置

此处为一个自动连续点击打开检查的自动化操作案例&#xff0c;没有quicker的鼠键录制&#xff0c;不常用了&#xff0c;做个备份 #MaxThreadsPerHotkey 2 ; 这个是核心&#xff01;&#xff01;&#xff01;&#xff01;确保可以同时运行多个热键或标签global isRunning : tru…...

Python安装环境变量

1、确保已经安装python到电脑上 2、到系统上环境变量位置 3、新建 系统变量&#xff0c;变量名为PYTHON_HOME&#xff0c;变量值为python安装目录 4、 点击系统变量的path&#xff0c;并新建环境变量 5、测试 &#xff0c;windowsR,并输入cmd&#xff0c;尝试命令python --ver…...

Flink同步数据mysql到doris问题合集

Flink同步数据mysql到doris 官方同步流程Doris安装下载地址导入镜像启动配置 Flink-cdc安装&#xff08;自制&#xff09;下载地址导入镜像启动命令 启动问题修复Flink报错Could not acquire the minimum required resources.作业报错 Mysql8.0 Public Key Retrieval is not al…...

Pytest测试用例执行跳过的3种方式

文章目录 1.前言2.使用 pytest.mark.skip 标记无条件跳过3.使用 pytest.mark.skipif 标记根据条件跳过4. 执行pytest.skip()方法跳过测试用例 1.前言 在实际场景中&#xff0c;我们可能某条测试用例没写完&#xff0c;代码执行时会报错&#xff0c;或者是在一些条件下不让某些…...

spring boot 连接FTP实现文件上传

spring boot 连接FTP实现文件上传 maven&#xff1a; <!--ftp--><dependency><groupId>commons-net</groupId><artifactId>commons-net</artifactId><version>3.8.0</version></dependency>接口示例&#xff1a; ApiO…...

深入解析/etc/hosts.allow与 /etc/hosts.deny:灵活控制 Linux 网络访问权限

文章目录 深入解析/etc/hosts.allow与 /etc/hosts.deny&#xff1a;灵活控制 Linux 网络访问权限引言什么是 TCP Wrappers&#xff1f;工作原理 什么是 /etc/hosts.allow 和 /etc/hosts.deny&#xff1f;匹配规则配置语法详解配置示例允许特定 IP 访问 SSH 服务拒绝整个子网访问…...

短跑怎么训练提高最快·棒球1号位

棒球运动员的短跑能力直接影响跑垒、防守和进攻效率&#xff0c;提升短跑速度需结合专项需求&#xff08;如爆发力、加速度、变向能力&#xff09;进行系统训练。以下为针对性训练方案&#xff1a; 一、专项爆发力训练&#xff08;提升起跑速度&#xff09; 抗阻冲刺 用弹力带…...