news 2026/10/3 20:55:39

高级数据库查询实战:从多表连接到窗口函数的SQL备考指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
高级数据库查询实战:从多表连接到窗口函数的SQL备考指南

备考计算机三级(数据库技术)的同学,十有八九会在交出一套 SELECT 语句后被批错。不是你不会写查询,而是高级数据库查询考的不只是语法,它考的是你对关系模型、分组逻辑和查询优化器的理解。很多人在这一步掉链子,不是输在语句背得少,而是输在一碰到“嵌套”“连接”“分组”就不知道哪个在前、哪个在后。

这篇备考记录,我按三级数据库考试里最常见的出题方式,把多表连接、嵌套子查询、集合运算、分组统计、窗口函数这些内容拆开讲,顺便把我自己刷题时踩过的坑和总结的速查模板一起放出来。适合正在备考三级数据库的同学,也适合工作里想补一补 SQL 基本功的人。文章里的例题我尽量统一在一套“学生选课”表结构上,这样你照着跑一遍,比干看书有效得多。

1. 高级数据库查询到底考什么

1.1 考试不是让你默写,是让你做取舍

很多备考资料把“高级查询”定义为“会写子查询、会 join、会 group by”,但这只是表面。三级数据库的题目往往不长,可挖的坑不少。真正的难点不是某个函数记不住,而是你能不能在一段模糊的业务描述里,快速判断该用哪张表、该用什么连接、该放在 WHERE 还是 HAVING。

我见过不少同学,天天背各种语句模板,一碰到“查询没有选修任何课程的学生”这种经典题就懵。原因很简单:他们背的是固定句式,而不是分析思路。高级查询题本质上考的是一种数据流转的顺序:先确定输出的列来自哪张表,再确定表与表之间怎么建立连接,接着确定过滤条件在哪一层做,最后才考虑要不要分组、要不要排序。

举个例子,题目问“查询选修了课程号 C001 且成绩不低于 90 分的学生姓名”。很多人拿到就写子查询,其实这里只需要一次简单的连接加过滤。真正需要做取舍的是“至少”“全部”“不存在”这类词,它们才对应 EXISTS、NOT EXISTS、集合运算等高级写法。所以第一步不是背语法,而是给题目里的关键词翻译成对应的 SQL 语义。

1.2 一张表看清各考点的比重

三级数据库的查询部分,考点其实是固定的。我按刷题和带教经验,把常见考点和出现频率整理成一张表,你可以拿它当复习清单。

考点类型典型问法考试出现频率推荐掌握程度
单表查询条件过滤、模糊匹配、排序必考必须熟练
多表连接两表或三表查询、左右外连接必考必须熟练
子查询IN、ANY、ALL、EXISTS、标量子查询高频必须熟练
集合运算UNION、INTERSECT、EXCEPT中频重点掌握
分组统计GROUP BY、HAVING、聚合函数高频必须熟练
窗口函数ROW_NUMBER、RANK、DENSE_RANK中低频扩展掌握
查询优化索引、执行计划、避免全表扫描中频理解原理

这张表的作用是帮你把精力分配得明明白白。单表查询和连接查询是地基,子查询和分组统计是拉开差距的地方,窗口函数则属于“别人不会你会”的加分项。备考时不要一上来就扎进冷门函数,先把高频考点做到闭着眼睛都能写。

2. 拿下多表连接:理解笛卡尔积才是赢家

2.1 连接查询到底在做什么操作

我在教学时经常问一个问题:当你写出一个 join 语句,数据库后台到底做了什么?很多人的回答是“把两张表合并起来”,这个说法太模糊。更准确的理解是,多表连接先对参与的表做一次笛卡尔积,再根据连接条件筛选出有效行。

笛卡尔积听起来吓人,其实就是“甲表的每一行去配对乙表的每一行”。比如 Student 表有 5 个学生,SC 表有 10 条选课记录,连接后数据量最多就是 5 × 10 = 50 行。如果三表连接,就是三张表行数的乘积。计算量很大,所以连接条件至关重要。

内连接之所以叫 inner,是因为它只保留连接条件成立的行。比如查学生姓名和选课成绩:

SELECT st.Sname, sc.Score FROM Student st JOIN SC sc ON st.Sno = sc.Sno;

这里的 ON 条件把师生信息和选课记录按学号对齐。写着简单,可很多人会在三表连接时翻车:

SELECT st.Sname, c.Cname, sc.Score FROM Student st JOIN SC sc ON st.Sno = sc.Sno JOIN Course c ON c.Cno = sc.Cno WHERE st.Dept = '计算机';

如果不写第二个 JOIN 的 ON,数据库会再次做笛卡尔积,结果立刻变成几十上百行。所以写多表连接时,我给自己定了一条死规矩:每写一个 JOIN,必须紧跟着写 ON,写完先数表间关系对不对,再往下写过滤条件。

2.2 外连接和自连接的实战姿势

内连接只是连接的一部分。题目里经常出现“不管有没有选课,都要把学生列出来”这种描述,这时候要用左外连接。左外连接以左表为主,右表没有匹配时,用 NULL 补齐。

SELECT st.Sname, sc.Score FROM Student st LEFT JOIN SC sc ON st.Sno = sc.Sno;

这句话能查出所有学生,没选课的学生成绩显示 NULL。它解决了一个很常见的需求:统计每个学生的选课门数,就算 dept 是 0,也不能把人丢掉。

这里隐藏着一个大考点:如果把过滤条件写在 WHERE 里,左连接就悄悄退化成内连接。比如:

SELECT st.Sname, sc.Score FROM Student st LEFT JOIN SC sc ON st.Sno = sc.Sno WHERE sc.Score > 60;

想象一下,一个学生没选任何课,SC 里根本没有对应记录,sc.Score 是 NULL。NULL > 60 的结果既不为真也不为假,WHERE 会把这一行过滤掉。结果就是没选课的学生又消失了。想保留左表的全部信息,过滤条件得写在 ON 里:

SELECT st.Sname, sc.Score FROM Student st LEFT JOIN SC sc ON st.Sno = sc.Sno AND sc.Score > 60;

外连接和 WHERE 的这层关系,是上机题里最容易丢分的点。我刷题时专门做过对比实验,同一个需求,过滤条件放 ON 和放 WHERE,结果完全不一样。

自连接也劝你别只背概念。最经典的例子是“同一张表里找年龄差距”。比如查询和“张小明”同系的学生,你可以用自连接,把一张表当成两张表用:

SELECT b.Sname FROM Student a JOIN Student b ON a.Dept = b.Dept WHERE a.Sname = '张小明' AND b.Sname <> '张小明';

自连接的精髓是给同一张表取不同的别名,让它在逻辑上变成两张表。这个技巧很多教材只是提个名字,但考试真考过。遇到“同一个表里的对比关系”,先想想能不能用自连接解决。

3. 子查询与集合运算:嵌套逻辑的拆解套路

3.1 单行子查询和多行子查询怎么区分

子查询本质上是把一条查询结果当作另一条查询的条件值。如果子查询只返回一个值,比如一个数字或一个字符串,它叫标量子查询:

SELECT Sname, Age FROM Student WHERE Age > (SELECT AVG(Age) FROM Student);

这个语句的含义是查所有年龄大于全校平均年龄的学生。子查询先算出平均年龄,比如 20.5,然后外层查询就用这个值去做比较。标量子查询结果唯一,判断关系可以用 =、>、< 这些普通运算符。

如果子查询返回多行,那就要用 IN、ANY、ALL 这些专门的运算符。它们的作用是让外层查询的某列值和子查询返回的一堆值逐一比较。比如查选修了 C001 或 C002 课程的学生学号:

SELECT Sname FROM Student WHERE Sno IN ( SELECT Sno FROM SC WHERE Cno IN ('C001', 'C002') );

这里子查询返回了多个学号,不能用等号直接比较。把多行结果和一个列做等值匹配时,IN 是最直观的选择。ANY 和 ALL 则不常用,但考试偶尔会考判断题。ANY 表示“至少满足其中一个”,ALL 表示“满足全部”。例如Score > ALL (子查询)意思是比子查询返回的所有分数都高,也就是比最大分数还高。

3.2 EXISTS 和 NOT EXISTS:真正的进阶分水岭

如果说 IN 是子查询的基础,EXISTS 就是高级查询的分水岭。EXISTS 特别适合“是否存在”这种判断,最典型的就是“查询没有选修任何课程的学生”。

SELECT st.Sname FROM Student st WHERE NOT EXISTS ( SELECT 1 FROM SC sc WHERE sc.Sno = st.Sno );

这段代码读起来有点绕,但核心逻辑很简单:对 Student 表的每一个学生,去 SC 表里找有没有他的选课记录。找到至少一条,EXISTS 就为真;一条都找不到,NOT EXISTS 就为真。

写 NOT EXISTS 时要注意一个细节:子查询里用了外层表的列,才能建立内外联系。这种写法叫相关子查询,子查询的执行依赖于外层当前行。很多人把子查询写成独立查询,结果发现查出来的数据莫名其妙,就是因为没有加WHERE sc.Sno = st.Sno。

我为什么更推荐 EXISTS 而不是 NOT IN?“查询没选课的学生”用 NOT IN 也能写:

SELECT Sname FROM Student WHERE Sno NOT IN (SELECT Sno FROM SC);

可这段代码有一个致命陷阱:如果 SC 表里的 Sno 存在 NULL 值,NOT IN 的结果会变成空。原因很绕,你可以简单理解成 NULL 不是任何值的“不等于”。考试专门喜欢出这种反直觉题,所以我的建议是:看到“没有”“不存在”“全部”这类词,优先用 NOT EXISTS。

3.3 集合运算:把查询结果当成集合

集合运算在三级考试里不考特别深,但 UION、INTERSECT、EXCEPT 这三兄弟经常出现在选择题里。它们的作用是把两个查询结果按行做合并、交集、差集。

查询“选修了 C001 或 C002 课程的学生”:

SELECT Sno FROM SC WHERE Cno = 'C001' UNION SELECT Sno FROM SC WHERE Cno = 'C002';

这句话和用 OR 写在同一个条件里的效果类似,但 UNION 会把重复行去掉。如果明确只想保留全部重复行,用UNION ALL,通常 UNION ALL 比 UNION 快,因为数据库不用专门去重。

INTERSECT 取两个结果的交集,适合“既选修了 C001,又选修了 C002”这类需求。EXCEPT 取差集,适合“选修了 C001,但没有选修 C002”这类需求。写集合运算时有一个规矩:每个 SELECT 语句输出的列数必须相同,数据类型尽量一致。仔细看题目给的选项,经常有人在 INTERSECT 后加 ORDER BY 却放错位置。ORDER BY 必须写在整套集合运算的最后,不是写在其中某一段后面。

4. 分组统计与 HAVING:别让 GROUP BY 毁在你手里

4.1 聚合函数为什么不能单独用在普通列上

分组统计是高级查询的常客,也是新手翻车重灾区。先记住一个原则:聚合函数是对一组值计算后返回单个值,比如 COUNT、SUM、AVG、MAX、MIN。当你使用了聚合函数,SELECT 里出现的普通列必须出现在 GROUP BY 子句里,否则数据库不知道怎么把这个普通列的值放到哪一行。

举个例子,统计每个系的学生人数:

SELECT Dept, COUNT(*) AS 人数 FROM Student GROUP BY Dept;

这里的 Dept 是分组列,COUNT(*) 是每一组的统计值。两相匹配,没问题。但如果有人写出SELECT Sname, COUNT(*) FROM Student GROUP BY Dept,这个语句在很多数据库里会直接报错,或者返回一个让人摸不着头脑的值。因为一个系有多个学生姓名,数据库不知道该取哪一个。考试题目常问“下面哪个语句是正确的”,考点往往就在这里。

聚合函数的使用也要留心,COUNT()、COUNT(列名)、COUNT(DISTINCT 列名) 语义完全不同。COUNT() 统计所有行,COUNT(列名) 只统计该列非 NULL 的行,COUNT(DISTINCT 列名) 统计去重后的非 NULL 值数量。选择题专门喜欢混淆这三者。

4.2 WHERE、GROUP BY、HAVING 的执行顺序

这是我反复讲过的一个点。SQL 的书写顺序和执行顺序并不一样,很多人不看执行顺序,只看书写顺序,结果在 WHERE 和 HAVING 上栽跟头。标准的逻辑执行顺序大致是:

  1. 先 FROM,确定数据来源。
  2. 再 WHERE,过滤原始行。
  3. 然后 GROUP BY,把过滤后的行分组。
  4. 接着 HAVING,过滤分组后的组。
  5. 再 SELECT,计算输出列。
  6. 最后 ORDER BY,对结果排序。

这个顺序解释了为什么“筛选分组前记录”用 WHERE,“筛选分组后结果”用 HAVING。比如统计选课门数大于 2 的学生:

SELECT Sno, COUNT(*) AS 选课数 FROM SC GROUP BY Sno HAVING COUNT(*) > 2;

这里 WHERE 已经没用了,因为选课数这个指标是分组之后才产生的。HAVING 针对的是“组”的过滤条件,它可以写聚合函数。WHERE 不行,因为 WHERE 执行时组还没形成。

一个常见的错误写法是:

SELECT Sno, COUNT(*) FROM SC WHERE COUNT(*) > 2 GROUP BY Sno;

这个语句逻辑上就是错的,聚合函数不能放在 WHERE 里做过滤。道理不难理解:WHERE 是在“逐行检查”的阶段执行,COUNT(*) 要等整组数据都到位才能算出来。

4.3 分组统计典型题目拆解

我拿一道近乎必考的题来练手:查询平均成绩高于 80 分且选修了至少两门课程的学生学号和平均成绩。

先不看答案,拆一下步骤:平均成绩和选课门数都是按学生分组后计算出来的,所以 GROUP BY Sno;每个组要被 HAVING 过滤,条件是 AVG(Score) > 80 且 COUNT(*) >= 2。

SELECT Sno, AVG(Score) AS 平均成绩, COUNT(*) AS 选课门数 FROM SC GROUP BY Sno HAVING AVG(Score) > 80 AND COUNT(*) >= 2;

这道题把分组的两个核心操作全考到了。如果题目要求再关联出学生姓名,就把查出来的学号再去 JOIN Student 表。注意 JOIN 的顺序:一般先过滤分组出符合条件的小结果集,再关联其他表,效率更高。不过考试里更看重逻辑,JOIN 写在前写在后结果一样。

5. 窗口函数:考场加分项,也是理解难点

5.1 PARTITION BY 和 ORDER BY 各自的工作

窗口函数是后来在数据库考试里逐渐出现的内容。它不是必须用 GROUP BY 压缩行数,而是在保留每一行原始数据的同时,对一组行做计算。最直观的需求是“按系排名”。

SELECT st.Dept, st.Sname, sc.Score, RANK() OVER (PARTITION BY st.Dept ORDER BY sc.Score DESC) AS 排名 FROM Student st JOIN SC sc ON st.Sno = sc.Sno;

PARTITION BY 负责分区,相当于对每个系单独起一个排行榜。ORDER BY 负责在每个分区内排序。这个查询不会减少行数,每个学生的原始记录还都在,只是多了一列排名。好多同学第一次看到结果时很惊讶:为什么行数没变少?这就是窗口函数和 GROUP BY 最大的不同。

GROUP BY 会把多行压成一行,窗口函数不会。所以窗口函数特别适合“既要明细数据,又要排名或累计值”的场景。

5.2 RANK、DENSE_RANK、ROW_NUMBER 的区别

这三个排名函数长得像,选择题最喜欢拿它们互相挖坑。ROW_NUMBER 就是单纯给每一行编一个连续序号,不管分数是否相同,序号从 1、2、3 依次往下排。RANK 遇到并列会跳号,比如两个人并列第一,那下一个人的名次是 3,不是 2。DENSE_RANK 遇到并列不跳号,下一个人还是 2。

函数相同值的处理方式典型结果示例
ROW_NUMBER强制给每行一个唯一序号1、2、3、4
RANK并列同号,且后续跳号1、1、3、4
DENSE_RANK并列同号,后续不跳号1、1、2、3

考试里“取出每个系成绩前 3 名”这类题,就需要想清楚用哪个函数。如果题目字面意思只是排名,通常 RANK 或 DENSE_RANK 更合理;如果只是按顺序取前 N 条,ROW_NUMBER 更直接。实际工作中,我经常先写 ROW_NUMBER 外层套一层再过滤,这样能精确定位某一档的记录。

5.3 窗口函数和 GROUP BY 的配合边界

窗口函数还能和 GROUP BY 一起出现,但要注意逻辑。比如先按学生分组算出平均分,再对这个平均分排名:

SELECT Sno, AVG(Score) AS 均分, RANK() OVER (ORDER BY AVG(Score) DESC) AS 均分排名 FROM SC GROUP BY Sno;

这里的 AVG(Score) 既是分组统计值,也是窗口函数里排序依据。窗口函数在所有分组、HAVING、聚合计算完成后才执行,所以能直接用 AVG(Score)。这道题我建议你亲手在 SQL Server 或 MySQL 8.0 以上跑一遍,跑一次比背十遍更管用。

6. 真题风格的查询设计:从题目到 SQL 的转化流程

6.1 三步读题法,把长题目翻译成执行计划

很多人看到大段文字描述就慌。我总结了一个“三步读题法”,应对三级数据库的查询大题基本够用。

第一步,看输出。题目要求显示哪些列,先写上 SELECT。比如“显示系名和人数”,SELECT 里一定先写这两列。第二步,看来源。输出列来自哪几张表,确定 FROM 和 JOIN。第三步,看条件。条件里如果有数字范围,通常是 WHERE;如果有“每个系”“每门课”这种词,通常是 GROUP BY;如果有“人数”“平均值”这种统计词,再决定 HAVING。

拿一个典型问题练手:查询每个系里选修了 C001 课程且成绩不低于 90 分的学生人数,显示系名和人数。

输出列是系名和人数。系名来自 Student 表,成绩来自 SC 表,所以两表连接。条件有两个,一个是 C001,一个是成绩不低于 90,都在分组之前过滤原始行,所以放 WHERE。最后按系分组。

SELECT st.Dept, COUNT(*) AS 人数 FROM Student st JOIN SC sc ON st.Sno = sc.Sno WHERE sc.Cno = 'C001' AND sc.Score >= 90 GROUP BY st.Dept;

很多人会把成绩条件放到 HAVING 里,因为句子里有“人数”。但这里过滤的是普通列 sc.Score,不是聚合结果,放 HAVING 反而逻辑不对。判断标准很简单:条件里出现的是原始列还是聚合函数,前者去 WHERE,后者去 HAVING。

6.2 另一个高频案例:没有选修任何课程的学生

这道题在各类题库里至少出现过十几次。业务描述是“查询没有选修任何课程的学生姓名”,考点是 NOT EXISTS 或 NOT IN 的取舍。

SELECT st.Sname FROM Student st WHERE NOT EXISTS ( SELECT 1 FROM SC sc WHERE sc.Sno = st.Sno );

这种题难就难在学生表里有些 Sno 可能在 SC 表里不存在,NOT EXISTS 对这种空值情况天然免疫。如果题目选项里出现用 NOT IN 的写法,你还要额外判断 SC 表的 Sno 会不会有 NULL。只要不能确定没有 NULL,NOT EXISTS 就是更稳的选择。

6.3 查询结果的验证习惯

写完 SQL 只成功了一半,另一半是验证。我备考时给自己定了一个规矩:先跑出结果,再手动核对几条数据。比如上面那道“每个系人数”的题,我会把 SC 表先按 C001 筛选,手工数一数计算机系有几个 90 分以上的人,再和查询结果对比。

这一步看着慢,实则是培养“数据敏感度”。考试上机环境里,你完全靠眼睛看不出结果对不对,但平时养成的核对习惯能帮你快速发现条件写错、连接条数不对这类低级错误。很多考生说自己“明明会写,就是考不出来”,其实就是验证这一步缺了。

7. 高频错误与排错经验:这些都是我踩过的坑

7.1 常见的六类查询翻车现场

我把平时刷题、带学生时遇到的典型错误整理成一张速查表,你可以把它贴在旁边备查。

错误类型错误示例原因分析正确思路
多表连接少写条件JOIN SC ON st.Sno = sc.Sno,少了 ON笛卡尔积导致结果爆炸每个 JOIN 后必须配 ON
左连接条件放错位置LEFT JOIN + WHERE 过滤右表列外连接退化成内连接保留左表所有行时放 ON
聚合函数放 WHEREWHERE COUNT(*) > 2WHERE 在分组前执行用 HAVING 过滤组
NOT IN 含 NULLSno NOT IN (子查询含 NULL)NULL 参与比较结果未定义优先用 NOT EXISTS
COUNT 列名统计COUNT(Score) 当 COUNT(*) 用NULL 不计入统计分清 COUNT 的语义
GROUP BY 后选普通列SELECT Sname, COUNT(*)普通列不在分组中只输出分组列或聚合值

这个表里的每一个坑,我都亲眼见过考生在模拟题里踩过。尤其左连接条件位置和 NOT IN 的 NULL 问题,出错概率非常高。

7.2 NULL 是隐藏的炸弹

NULL 在 SQL 里不是空字符串,也不是 0,它代表“未知”。凡是和 NULL 做比较的表达式,结果都是 UNKNOWN,既不是 TRUE 也不是 FALSE。所以WHERE Score > 60会把成绩为 NULL 的行过滤掉,WHERE Score = NULL也查不出任何行,必须用IS NULL来判断。

NULL 另一个隐蔽地点是聚合函数。COUNT(Score) 不统计 NULL,但 SUM、AVG 遇到 NULL 又会忽略它。比如统计某门课的平均分,如果某些学生没成绩被记成 NULL,直接 AVG(Score) 会把它们跳过,结果可能和学生人数对不上。这不算错,但你要知道这个规则,才能解释为什么查出来的平均值“偏高”。

7.3 书写顺序和执行顺序要分开记

SELECT、FROM、WHERE、GROUP BY、HAVING、ORDER BY 这个书写顺序大家都熟,但数据库真正执行时是反着来的:FROM 最先确定数据源,然后 WHERE 过滤,再 GROUP BY 分组,再 HAVING 过滤组,然后 SELECT 计算输出,最后 ORDER BY 排序。我一直强调这个逻辑,是因为很多语句报错或结果不符合预期,都是因为把执行顺序和书写顺序搞混。

比如有人想过滤掉分组后人数小于 2 的组,却把条件写在 WHERE 里;又比如 SELECT 里给某列取了别名,却在 WHERE 里直接用别名。WHERE 执行时,SELECT 里的别名还没生成,当然会报“列名无效”。理解执行顺序之前,这些问题只能用死记硬背应付;理解之后,你自然就知道该往哪儿写。

7.4 一个值得养成的刷题习惯

备考后期,我给自己做了一个小调整:不再对着答案看题,而是把每道选择题都当成“手写 SQL 题”来推演。先看题目问什么,自己脑子里写一遍 SQL,再看选项里哪个和自己的思路一致。这样做的好处是,选择题里的很多“错误答案”其实都是某些同学的典型错法,你能看出它错在哪,就和出题人站在同一位置了。

我还建议你把每个经典例题都准备一个测试脚本,重复跑、刻意拆解。比如今天我写的 Student、Course、SC 三张表,你可以往 SC 表里插入几个空学号记录,试试 NOT EXISTS 和 NOT IN 的差异;也可以把 LEFT JOIN 的 ON 和 WHERE 各写一遍,对比结果行数。亲手改动一次,比看十遍文章印象深得多。三级数据库的高级查询并不玄学,说到底就是“连接、子查询、分组、集合、窗口”这几件事的组合。你只要把每个模块的底层逻辑打通,再配合适量题目训练,考场上看到再长的描述,也能很快拆成可执行的一步一步。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/3 20:54:17

分布式系统开发实战:锁、事务、缓存与分布式ID解析

1. 分布式架构&#xff1a;先摸清“团建”的底层逻辑分布式系统这个词&#xff0c;在技术圈被聊得最多&#xff0c;也最容易被聊糊。一搜“分布式”&#xff0c;出来的全是分布式锁、分布式事务、分布式缓存、分布式架构、分布式爬虫、分布式定时任务、分布式UUID……知识点碎得…

作者头像 李华
网站建设 2026/10/3 20:54:17

ArcGIS Pro样式迁移:.style转.stylx实操指南

ArcGIS Pro 出来这么多年了&#xff0c;我相信不少同行手里还攥着一大批老项目攒下来的 .style 样式库。前阵子帮一个兄弟单位迁移制图环境&#xff0c;对方工程师一上来就问&#xff1a;这一堆 .style 能不能直接拖进 Pro 里用&#xff1f;我当场就笑了——能拖&#xff0c;但…

作者头像 李华
网站建设 2026/10/3 20:54:16

Redis为什么这么快?从内存存储到IO多路复用的性能设计解析

1. 先弄清楚“Redis快”到底快在哪聊Redis&#xff0c;绕不开那句老话&#xff1a;Redis为什么这么快。很多人第一反应是“因为数据放在内存里”&#xff0c;这当然没错&#xff0c;但远远不够。内存数据库又不是只有Redis一家&#xff0c;Memcached也把数据放在内存里&#xf…

作者头像 李华
网站建设 2026/10/3 20:54:13

前端跨子域通讯实战:从postMessage到代理页的选型与踩坑

最近在做两个子系统的整合改造&#xff0c;被"前端跨子域通讯"这件事实打实恶心了两周。场景并不复杂&#xff1a;用户在 a.example.com 登录&#xff0c;跳转到 b.example.com 后要保持登录态、同步用户偏好&#xff0c;同时 b 站点修改的资料要反写回 a 的展示层。…

作者头像 李华
网站建设 2026/10/3 20:47:46

Node.js全栈实战:天远车牌查询API从接入到上线

现在不少做车辆管理、出行服务、二手车核验的朋友都在找车牌查询接口&#xff0c;但真正能把整套调用流程跑通、并且知道怎么接到自己业务里的人其实不多。这个标题里提到的天远名下车辆车牌查询API&#xff0c;本质上是把“输入车牌号 -> 返回车辆基础信息”这个能力封装成…

作者头像 李华
网站建设 2026/10/3 20:21:27

PyTorch工程化骨架:可复现、易协作、防坑的工业级代码框架

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华