尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

MySQL排序分组限制:从执行顺序到实战一次讲透

MySQL排序分组限制:从执行顺序到实战一次讲透 1. 为什么排序、分组、限制是SQL入门的第一道坎刚接触MySQL的人十有八九是被这三个操作同时卡住的ORDER BY排序、GROUP BY分组、LIMIT限制条数。单拿出来每一个都能看懂一旦组合在一起脑子里就成了一团浆糊——先执行谁、后执行谁为什么分组之后排序结果不对为什么加了GROUP BY之后查出来的数据变少了这些问题几乎每天都能在技术群里看到有人问。这篇文章要做的就是把这三块内容串起来讲透。不是给你扔一堆语法让你背而是从执行逻辑出发让你明白SQL这条查询语句到底按什么顺序干活搞懂了底层顺序语法自然就记住了。文章默认你连MySQL都没装过也能跟上——不过既然涉及实操建议你打开终端敲几行命令光看不练记不牢。我用的是MySQL 8.0版本以下所有语法在5.7版本同样适用两者在基础排序和分组上没有任何差别。先说结论一句话概括三者的关系ORDER BY控制输出长什么样GROUP BY控制按什么维度汇总LIMIT控制最终拿多少行。但这个结论太粗糙实际使用中藏着大量细节。接下来的内容从最基础的排序讲起逐步推进到分组聚合最后把三者组合起来给你一套完整的实战套路。2. ORDER BY排序别只会升序降序2.1 最简单的排序列子打开你的MySQL随便建一张测试表。如果不想手动建表直接用下面这段CREATE TABLE student ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(20), class VARCHAR(20), score INT ); INSERT INTO student (name, class, score) VALUES (小明, 一班, 85), (小红, 二班, 92), (小刚, 一班, 78), (小丽, 二班, 88), (小华, 三班, 95), (小强, 三班, 67);现在需求来了想按分数从高到低列出所有学生这条SQL是第一步SELECT * FROM student ORDER BY score DESC;DESC代表降序从大到小ASC代表升序从小到大默认是升序所以ORDER BY score不加任何修饰结果就是从小到大排。这里有个初学者最容易犯的错——以为ORDER BY必须放在WHERE后面。实际上只要ORDER BY在整条SQL的最末尾LIMIT之前它放在哪一行写都一样因为SQL的执行顺序和书写顺序是两回事。下面这段也是正确的SELECT * FROM student WHERE score 80 ORDER BY score DESC;2.2 多字段排序理解排序的优先级光按一个字段排大多数场景不够用。比如分数一样的情况下想按名字拼音再排一下这时需要写多个排序字段SELECT * FROM student ORDER BY score DESC, name ASC;这段SQL的意思是先按score降序排如果score相同再按name升序排。你可以这样理解排序的执行机制——MySQL先把所有行按第一个字段排好排完之后发现有些行的score相等这些相等的行内部再按第二个字段排序以此类推。实际工作中最常见的多字段排序场景是排行榜积分相同比胜场胜场相同比净胜分。用SQL写就是SELECT * FROM ranking ORDER BY points DESC, wins DESC, goal_diff DESC;这里有一个隐藏细节ORDER BY后面跟的字段必须是SELECT后面能查出来的字段或者是表里真实存在的字段。如果你在SELECT里用别名ORDER BY是可以直接用别名的SELECT name, score * 2 AS double_score FROM student ORDER BY double_score DESC;能用别名是因为ORDER BY的执行顺序在所有计算完成之后所以拿别名做排序列没有任何问题。2.3 字符串排序的坑为什么中文排序结果怪怪的按中文字段排序是零基础玩家经常踩的坑。看这个需求——按学生姓名排序你可能会写SELECT * FROM student ORDER BY name;查出来的结果大概率不是你想的拼音顺序。MySQL对中文字符串的默认排序取决于字符集和排序规则在utf8mb4_general_ci这种常见排序规则下中文排序基本是按字符编码的二进制值排的结果既不是拼音顺序也不是笔画顺序看起来就像随机排列。解决中文排序问题的常用方式是用CONVERT函数把字段转成gbk编码再排序SELECT * FROM student ORDER BY CONVERT(name USING gbk);转换之后MySQL会按拼音顺序排列。原理是GBK编码的中文字符顺序就是拼音顺序所以转码之后再排序就成了变通的拼音排序法。不过这个方法对生僻字和多音字仍然会有偏差而且转换后无法使用索引数据量大时性能较差生产环境慎用学习阶段能用明白原理就够了。顺带说一个相关热搜里的高频问题C如何在排序的情况下取一个vector中最小的十个元素。这个用C写可以partial_sort但MySQL里对应的需求是取成绩最低的十个学生后面讲LIMIT时会一起解决。3. GROUP BY分组分组的本质是“去重汇总”3.1 分组到底做了什么GROUP BY是初学者最困惑的关键字因为它的执行效果和直观理解有偏差。很多人以为分组就是把数据拆成几个小组展示出来但实际执行时每一组只保留一行这一行是整组数据的代表。执行逻辑是MySQL扫描全表把GROUP BY字段值相同的所有行归为一组然后每组输出一行。如果想看每组里其他字段的具体值必须用聚合函数配合否则查出来的那一行并没有参考意义。举个最典型的例子——统计每个班的学生人数SELECT class, COUNT(*) AS num FROM student GROUP BY class;结果类似这样classnum一班2二班2三班2COUNT(*)统计的是每组内的行数也就是每个班的学生数量。3.2 为什么分了组就只能查分组字段和聚合函数这是GROUP BY最核心的语法限制。看这条错误SQLSELECT name, class, COUNT(*) FROM student GROUP BY class;MySQL会直接报错错误信息大致是name字段不在GROUP BY子句中。原因很简单分了组之后每个组有多个nameMySQL不知道你想显示哪个name。除非你告诉它比如用MAX(name)取第一个或者用GROUP_CONCAT(name)把组内所有名字拼起来。ONLY_FULL_GROUP_BY是MySQL 5.7.5之后默认开启的SQL模式这个模式禁止了上述写法。如果你想关闭这个限制可以执行SET sql_mode (SELECT REPLACE(sql_mode, ONLY_FULL_GROUP_BY, ));但我不建议你关掉它——这个模式能强制你理清逻辑避免查出无意义的数据。分组的场景里最常用的聚合函数有五个COUNT(*)统计行数SUM(字段)求和AVG(字段)求平均MAX(字段)取最大MIN(字段)取最小这些函数和GROUP BY配合几乎能覆盖所有汇总统计需求。统计每班平均分SELECT class, AVG(score) AS avg_score FROM student GROUP BY class;统计每班最高分和最低分SELECT class, MAX(score) AS max_score, MIN(score) AS min_score FROM student GROUP BY class;3.3 多列分组百分比分组这类需求就是靠它实现的热搜词里有一条百分比分组实际工作中你可能会遇到这种需求按分数段统计人数比如60以下、60到80、80到90、90以上各有多少人。这种需求本质上就是要造一个分组字段然后用CASE WHEN语句解决SELECT CASE WHEN score 60 THEN 不及格 WHEN score 80 THEN 及格 WHEN score 90 THEN 良好 ELSE 优秀 END AS level, COUNT(*) AS num FROM student GROUP BY level;注意最后一行是GROUP BY level这里的level是SELECT中CASE WHEN表达式生成的别名。MySQL允许在GROUP BY中使用SELECT里的别名这一点比WHERE灵活得多WHERE里不能用别名。多列分组的语法也很直白比如按班级和性别两个维度统计人数SELECT class, gender, COUNT(*) FROM student GROUP BY class, gender;它的语义是class和gender两个字段都相同的行归为一组。多列分组的执行流程和单列一样只是分组依据从一列变成了多列的组合值。我认为理解分组最关键的一步是接受每组只出一行这个设定。你一旦想明白这一点后面HAVING的用法就顺理成章了——WHERE是分组之前过滤行HAVING是分组之后过滤组。3.4 分组排序的组合每组排序的伪需求与真实现有人问MySQL怎么对每组内的记录分别排序比如每个班按分数从高到低列出前三名。这个需求不能直接靠GROUP BY实现因为分组后每组只剩一行组内排序无从谈起。正确的做法是用窗口函数MySQL 8.0才支持用ROW_NUMBER()给每组内的行编号SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY class ORDER BY score DESC) AS rn FROM student ) AS t WHERE rn 3;用生活化类比解释这一段的执行逻辑PARTITION BY class把学生按班级分开每个班级内部是一个独立的小队列ORDER BY score DESC让每个小队列按分数从高到低站好ROW_NUMBER()给队列里的每个人发号码牌分数最高的拿1号外层查询再把号码牌大于3的筛掉剩下就是每班前三名。如果你用的是MySQL 5.7窗口函数用不了可以靠自关联变量实现相同效果但那种写法比较复杂基础阶段不推荐碰等把窗口函数学明白再回来补5.7的解法会轻松很多。4. LIMIT限制截取数据行的超实用语法4.1 LIMIT的两种写法LIMIT是英语单词限制的意思作用就是截取查询结果中的指定行数。写法有两种效果完全一样-- 写法一只写行数从第一行开始取 SELECT * FROM student LIMIT 3; -- 写法二写偏移量和行数从第4行开始取3行 SELECT * FROM student LIMIT 3, 3; -- 写法三带有OFFSET关键字语义更清晰 SELECT * FROM student LIMIT 3 OFFSET 3;写法一取出第1、2、3行写法二和写法三都是跳过前3行取出第4、5、6行。这里有一个非常容易混淆的点LIMIT 3, 3中的第一个3是偏移量代表跳过几行不是起始行号——如果把它理解成从第3行开始取就大错特错了。4.2 分页查询LIMIT的灵魂用法分页是LIMIT最经典的应用场景。每页显示10条数据查询第3页的SQL长这样SELECT * FROM student LIMIT 20, 10;偏移量20来自(页码 - 1) * 每页条数(3-1)*1020。热搜词里的navict限制查询条数指的就是Navicat这个客户端工具自带的一个限制防止一次查出几十万行数据把电脑卡死。这个限制在Navicat的查询编辑器的LIMIT区域可以设置默认是1000条可以调大调小但哪怕调大到10000它依然是个防呆限制和SQL里的LIMIT关键字是两码事别混淆。4.3 取最大值和最小值ORDER BY加LIMIT组合拳SEO优化、排行榜、热门文章这些场景里最常见的需求就是取前N名。语法永远是同一种套路-- 成绩最高的三个学生 SELECT * FROM student ORDER BY score DESC LIMIT 3; -- 成绩最低的两个学生 SELECT * FROM student ORDER BY score ASC LIMIT 2;结合前面说的C取最小十个元素的热搜MySQL版就是SELECT * FROM student ORDER BY score ASC LIMIT 10;4.4 分组后每组取前N条LIMIT的进阶场景我在第3.4节提到了用窗口函数解决每组取前N条那里只用了ROW_NUMBER()这里把完整方案展开讲一次。假设要在学生表里找出每个班分数最高的学生SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY class ORDER BY score DESC) AS rn FROM student ) AS t WHERE t.rn 1;这种写法把分组、排序、限制三个核心操作串在了一条完整的SQL里逻辑层次非常清晰内层负责分组编号外层负责截取。学完这篇文章你会发现这个例子是检验自己是否真正理解三者关系的最好练习题。4.5 LIMIT在大表场景下的性能隐患LIMIT看起来简单但在数据量大的表上直接用性能问题非常明显。假设student表有1000万行数据执行SELECT * FROM student ORDER BY score DESC LIMIT 10;MySQL会先把1000万行全部按score排序然后才取前10行返回。排序成本是巨大的更不用说如果没有合适的索引支撑排序过程可能在磁盘上完成慢到让你怀疑数据库是不是挂了。针对这种场景优化思路是给排序字段建索引CREATE INDEX idx_score ON student(score);这样MySQL可以直接利用索引的有序性从头读取10行返回无需额外排序。索引的本质是把无序的数据变成有序排列的目录对ORDER BY性能的提升是数量级的。对于深度分页即偏移量非常大的情况比如LIMIT 900000, 10即使有索引也会慢因为MySQL必须扫描前900010行再扔掉前900000行。业界常见的优化方案是延迟关联或者基于游标的分页但这两者涉及更高级的调优知识零基础阶段先记住分页越深越慢需要靠索引解决这个结论就够了。5. WHERE、GROUP BY、HAVING、ORDER BY、LIMIT的执行顺序5.1 一条SQL的执行顺序全景图这一节是整个零基础入门阶段最值得反复看的内容。知道了执行顺序你就掌握了SQL查询的上帝视角。上面所有关键字的实际执行顺序是这样的FROM确定从哪张表取数据WHERE逐行过滤把不满足条件的行删掉GROUP BY按字段分组每组保留一行HAVING分组之后再过滤删除不满足条件的组SELECT计算要显示的字段和聚合值ORDER BY对上一步的结果排序LIMIT从排序后的结果中截取指定行数这里最反直觉的一点是WHERE比GROUP BY先执行所以WHERE里不能使用聚合函数因为它执行时还没分组呢而HAVING比GROUP BY后执行所以HAVING里可以使用聚合函数。这就是为什么同样的条件写在WHERE和HAVING里效果可能完全不同。看一个具体例子。统计每个班平均分大于80的班级SELECT class, AVG(score) AS avg_score FROM student GROUP BY class HAVING AVG(score) 80;如果把HAVING AVG(score) 80换成WHERE AVG(score) 80MySQL会直接报错。因为执行WHERE的时候还没分组哪来的AVG(score)同理如果想只统计分数大于70的学生再按班级分组那应该用WHERE先过滤掉低分学生SELECT class, AVG(score) AS avg_score FROM student WHERE score 70 GROUP BY class;5.2 WHERE和HAVING的边界感看到这里你可能已经感受到了WHERE和HAVING的分工是清晰的WHERE管行HAVING管组。一个查询里完全可以同时用这两者。比如要找出平均分大于80、且人数至少2人的班级SELECT class, AVG(score) AS avg_score, COUNT(*) AS num FROM student WHERE score 60 GROUP BY class HAVING AVG(score) 80 AND COUNT(*) 2;这条SQL的执行过程我用生活类比给你讲透先把所有及格的学生挑出来WHERE score 60这是第一轮筛选然后按班级分组GROUP BY class每个班聚成一堆接着对每个班做第二轮筛选平均分超过80且人数不少于2人的班才留下来HAVING最后把每个班的班级名、平均分、人数输出按平均分降序排列。5.3 ORDER BY和LIMIT在分组之后怎么配合一个完整的综合场景可以把本文所有知识点串起来。需求找出所有及格学生中人数最多的前两个班按人数从多到少排列。SELECT class, COUNT(*) AS num FROM student WHERE score 60 GROUP BY class ORDER BY num DESC LIMIT 2;执行顺序分析WHERE score 60过滤掉不及格的GROUP BY class按班级分组每班输出一行计算每班人数COUNT(*)ORDER BY num DESC按人数降序LIMIT 2只取前两个班5.4 一个初学者的常见误区分组的WHERE写法位置前面说了WHERE在GROUP BY前面执行相应的书写顺序也是固定的WHERE必须出现在GROUP BY之前。SQL语法对关键字的书写顺序是有严格规定的不能随意调换-- 正确 SELECT class, COUNT(*) FROM student WHERE score 60 GROUP BY class; -- 错误WHERE写在了GROUP BY后面 SELECT class, COUNT(*) FROM student GROUP BY class WHERE score 60;这个语法错误很能说明问题——书写顺序必须和执行顺序保持一致先过滤再分组语法上也就必须是WHERE在前。6. 实战场景串讲一个需求打通全部语法6.1 构造一个稍微复杂的业务表纸上谈兵讲完了来一个完整的实战练习。假设你是一家在线教育公司的运营数据库里有一张订单表ordersCREATE TABLE orders ( id INT PRIMARY KEY AUTO_INCREMENT, course_name VARCHAR(50), category VARCHAR(20), price DECIMAL(10,2), pay_time DATETIME ); INSERT INTO orders (course_name, category, price, pay_time) VALUES (MySQL零基础入门, 数据库, 99.00, 2025-01-05 10:23:00), (SQL优化实战, 数据库, 199.00, 2025-01-08 14:02:00), (Python入门, 编程, 129.00, 2025-01-09 09:15:00), (数据分析基础, 数据分析, 159.00, 2025-02-01 20:30:00), (MySQL进阶, 数据库, 299.00, 2025-02-03 11:45:00), (Excel办公实战, 办公, 79.00, 2025-02-05 16:20:00), (Python爬虫, 编程, 199.00, 2025-02-15 13:50:00), (机器学习入门, 人工智能, 399.00, 2025-03-01 09:00:00), (Pandas数据处理, 数据分析, 179.00, 2025-03-05 15:30:00), (SQL调优实战, 数据库, 249.00, 2025-03-10 10:10:00), (Python自动化办公, 编程, 149.00, 2025-03-12 18:00:00), (MySQL运维实战, 数据库, 349.00, 2025-03-20 21:00:00);现在陆续有运营需求提过来我们一条一条用SQL解决。6.2 需求一统计各类别课程的数量和总销售额SELECT category, COUNT(*) AS course_cnt, SUM(price) AS total_sales FROM orders GROUP BY category ORDER BY total_sales DESC;这条SQL用到了分组、聚合、排序、别名核心价值在最后一行的ORDER BY total_sales DESC这里直接使用了SELECT中定义的别名total_sales再次验证了ORDER BY执行顺序在所有字段计算之后。6.3 需求二找出销售额超过300元的类别并只统计筛选后的数据这里要先把价格低于100元的课程过滤掉再按类别分组然后筛选总销售额超过300的类别SELECT category, COUNT(*) AS course_cnt, SUM(price) AS total_sales FROM orders WHERE price 100 GROUP BY category HAVING SUM(price) 300 ORDER BY total_sales DESC;为什么这里必须用HAVING而不能把SUM(price) 300放进WHERE因为SUM(price)是按类别分组之后才计算出来的聚合值WHERE执行时压根没有SUM的概念。执行时序决定了语法选择这个概念理解了分组的所有难点都迎刃而解。6.4 需求三找出销售额TOP 3的课程类别在上一段基础上加一行LIMITSELECT category, COUNT(*) AS course_cnt, SUM(price) AS total_sales FROM orders WHERE price 100 GROUP BY category HAVING SUM(price) 300 ORDER BY total_sales DESC LIMIT 3;看这条SQL的执行链路WHERE过滤低价课程GROUP BY分组HAVING过滤低销售额分组ORDER BY排序LIMIT截断五个关键字在一条语句里完成了完整的筛选—分组—聚合—过滤—排序—截断管线。能完整看懂这条SQL的每个执行步骤你的零基础阶段就算毕业了。6.5 需求四查询每月销售额格式化成百分比增长热搜词里有一条百分比分组我把它升级成更完整的统计场景。先统计每个月的销售额SELECT DATE_FORMAT(pay_time, %Y-%m) AS month, SUM(price) AS monthly_sales FROM orders GROUP BY month ORDER BY month;这里注意GROUP BY month用的是别名MySQL允许这么写。如果还想看每个月的销售额占比可以配合窗口函数SELECT DATE_FORMAT(pay_time, %Y-%m) AS month, SUM(price) AS monthly_sales, SUM(price) / SUM(SUM(price)) OVER () * 100 AS pct FROM orders GROUP BY month;这个需求对零基础来说有点超纲但理解起来不算太难SUM(SUM(price)) OVER ()把所有月份的销售额加总然后每个月的销售额除以这个总数再乘100就是百分比占比。真正的系统学习时这类窗口函数会是你接下来进阶的重要内容。7. 排序分组限制的避坑指南那些让我调试到崩溃的问题7.1 NULL值在排序中的默认位置排序时最容易被忽略的是NULL值。默认情况下MySQL的ORDER BY升序排序会把NULL排在最前面降序则把NULL排在最后面。也就是说NULL在MySQL的排序逻辑里被视为最小值。如果业务上想把NULL当作最大值比如没有填写时间的记录排在最前面需要额外处理SELECT * FROM orders ORDER BY pay_time IS NULL, pay_time DESC;pay_time IS NULL这个表达式的值要么是1要么是0排序时1会被排在0后面所以NULL的订单就排到了后面。悬而未决的最优解其实没有标准答案取决于业务需求希望你如何处理缺数据的情况。但这恰恰是实际开发中容易出bug的地方——测试数据里没有NULL一到生产环境就有大量空值排序结果完全变样。7.2 DISTINCT和GROUP BY的混淆求有多少个不同类别时很多初学者会卡在DISTINCT和GROUP BY之间SELECT DISTINCT category FROM orders; SELECT category FROM orders GROUP BY category;从结果集看两条SQL返回的行一样都是去掉重复类别后的列表。两者的区别在于GROUP BY常配合聚合函数使用而DISTINCT通常只用来去重没有聚合能力。性能层面两者在大多数情况下会被优化器换成同一种执行计划差别不大。但有一个场景两者差异巨大如果你需要每个类别后面带上课程数量那只能靠GROUP BY加COUNT(*)DISTINCT永远做不到。7.3 排序和索引的相爱相杀给ORDER BY字段建索引能提速这个前面讲过但有一个前提如果排序字段上加了函数比如ORDER BY CONVERT(name USING gbk)索引就失效了。这是因为索引是按照字段原始值建立的字段被函数处理后索引里的顺序和函数结果没有任何关系优化器只能放弃索引。解决思路有两种一是让应用层做中文字段的拼音转换把拼音列单独存一列并建立索引二是使用支持中文拼音排序的排序规则。这两种方案都比每次查询临时转码靠谱生产环境我也见过直接用转码方式的数据量小的时候问题不大数据量上来后必然出事。7.4 LIMIT的偏移量陷阱分页查询的偏移量越深越慢这个陷阱我在第4.5节已经提过但它的影响面比预期大。除了深度分页的性能问题还有一个逻辑问题一旦数据在两次分页请求之间发生了变化下一页的数据可能和上一页有重叠或者直接跳过了某条新插入的记录。解决这个问题的通用做法是游标分页也就是用上次查询的最后一条记录的某个唯一字段作为下次查询的起始条件-- 第一页 SELECT * FROM orders ORDER BY id LIMIT 10; -- 第二页假设第一页最后一条记录的id是100 SELECT * FROM orders WHERE id 100 ORDER BY id LIMIT 10;这种写法不仅避免了偏移量深挖导致的性能问题还能保证数据一致性当下的分页接口设计里这是推荐方案。7.5 重复分组名的清理字符串那点事GROUP_CONCAT配合分组可以把组内的字段值连成一个字符串输出SELECT class, GROUP_CONCAT(name) AS students FROM student GROUP BY class;结果集大概长这样classstudents一班小明,小刚二班小红,小丽三班小华,小强如果你觉得逗号分隔不够美观可以指定分隔符SELECT class, GROUP_CONCAT(name SEPARATOR 、) FROM student GROUP BY class;热搜词里的foxmail怎么按联系人分组邮件思路本质上就是先按联系人分组再把属于同一联系人的多封邮件聚到一起用GROUP_CONCAT把邮件主题拼在一起甚至能直接当简报看。8. 从零基础到能上手一套刻意练习的建议路径看到这里相信你已经理解了基本的语法和执行顺序。但理解归理解写SQL就像骑自行车脑子会了手不一定会。我给你一套刻意练习的路径每天二十分钟一个星期基本就能有把握地处理日常的排序分组需求。第一轮把文中的所有SQL自己手动敲一遍注意是手动敲不是复制粘贴先试试能否一字不差写出来。敲的过程中重点关注关键字顺序——WHERE在GROUP BY前GROUP BY在HAVING前HAVING在ORDER BY前ORDER BY在LIMIT前。第二轮自己构造场景。随便找一张真实存在的数据表或者用文中的student表和orders表给自己出十道题覆盖以下类型按某字段排序再加第二排序字段按某字段分组统计每组的数量、总和、平均值用WHERE先过滤再分组用HAVING过滤分组后的结果找出每组内的最大值和最小值用LIMIT做分页用ORDER BY加LIMIT取前N名用窗口函数给组内编号取每组前N条第三轮造出一批NULL值数据重复上述练习观察排序结果的变化。把表数据量造到十万行以上体验LIMIT的深度分页性能瓶颈再尝试用索引优化。练习时建议开启MySQL的慢查询日志看到真实执行时间会更直观地理解索引对排序的重要影响。查看一条SQL的执行计划可以用EXPLAIN SELECT * FROM orders ORDER BY price DESC LIMIT 10;EXPLAIN输出的Extra列如果出现Using filesort说明MySQL正在做一次额外的文件排序这种SQL性能往往不够好。按这个节奏练下来你会发现所谓零基础速成不是背语法而是通过反复的场景—SQL—结果对照让大脑形成条件反射。到那时再遇到任何排序、分组、限制的需求直接提笔就写不会再卡壳。
返回列表