问题

怎样才能写出高质量的SQL语句?

回答
好的,咱们这就来聊聊怎么才能写出那些读起来顺畅、跑起来飞快、维护起来省心的SQL语句,保证你说出来的时候,同事们都会眼前一亮,甚至有点小崇拜。这事儿说起来,可不是东拼西凑几条命令就行,里面门道可多着呢。

一、 理解你的“敌人”:数据库和数据

在提笔写SQL之前,最最重要的一步,就是要透彻理解你要打交道的数据库长什么样,里面装的是什么数据。这就像上战场,不了解地形和敌情,怎么打?

表结构(Schema): 详细看看每个表的字段名、数据类型、有没有主键、外键、索引。了解字段之间的关系,比如一个订单对应几个商品,一个用户有多少个地址。
数据量和分布: 同样的数据,在几十万行和几亿行面前,处理方式完全是天壤之别。你的查询是会扫描全表,还是能通过索引快速定位?数据是均匀分布,还是某个值特别多?
业务逻辑: 你的SQL到底是要解决什么业务问题?是统计用户的活跃度?计算销售额?还是找出某个特定条件下的商品?明确的业务目标能帮你避免写出“跑偏”的SQL。
数据库类型和版本: SQL语法在大体上是通用的,但不同数据库(MySQL, PostgreSQL, Oracle, SQL Server等)以及它们的版本,在一些函数、特性、性能优化上会有差异。了解你用的“家伙事”,才能用好它。

二、 结构清晰,易读为王

SQL语句不是给机器看的,最终还是要给人看的,特别是那些后来维护你代码的同事(或者几个月后的你自己)。

1. 缩进和换行: 这是最基本也是最重要的。
`SELECT`、`FROM`、`WHERE`、`GROUP BY`、`ORDER BY`、`HAVING` 等关键字,每一层逻辑都应该有明确的缩进,让语句结构一目了然。
长一点的SQL,把条件、连接、聚合等逻辑拆开,用换行隔开,读起来就不会像一坨密密麻麻的代码。

举个反例:
```sql
SELECT a.name,b.order_date FROM users a JOIN orders b ON a.user_id=b.user_id WHERE a.city='Beijing' AND b.amount > 100 ORDER BY b.order_date DESC;
```
改进后:
```sql
SELECT
u.name, 用户姓名
o.order_date 订单日期
FROM
users u 用户表,别名 u
JOIN
orders o ON u.user_id = o.user_id 通过用户ID关联订单表,别名 o
WHERE
u.city = 'Beijing' 只看北京的用户
AND o.amount > 100 订单金额大于100
ORDER BY
o.order_date DESC; 按订单日期降序排列
```
你看,加了别名,加了注释,格式清晰,是不是舒服多了?

2. 命名规范(别名):
给表和字段起简洁、有意义的别名。通常用表名的首字母缩写(如 `users` > `u`,`orders` > `o`),或者能概括字段含义的词(如 `order_total_amount` > `total_amount`)。
避免使用太短或者容易混淆的别名,比如 `a`, `b`, `c`,除非在非常简单的查询中。

3. 注释:
关键逻辑、复杂的计算、业务含义不明显的字段,一定要加上注释。
`` 用于单行注释,`/ ... /` 用于多行注释。
注释要说明“为什么”这么做,而不是“做了什么”(做了什么从代码里就能看出来)。

三、 性能优化,让它跑得快

写出能运行的SQL是基础,写出运行高效的SQL才是高手。

1. 索引,索引,索引!
where 子句中的条件: 凡是出现在 `WHERE` 条件里的字段,如果该字段的选择性高(即不同值的数量多),并且经常用于过滤,那么给它建索引几乎是必选项。
JOIN 条件: 用于连接两个表的字段(通常是外键),也应该考虑建立索引,这样数据库在查找匹配项时会快很多。
ORDER BY 和 GROUP BY: 如果经常对某个字段进行排序或分组,给这个字段建立索引可以大大加速。
覆盖索引(Covering Index): 如果查询中需要的所有字段都在索引中,数据库就不用再去主表中回表查询,性能会显著提升。
避免在索引字段上使用函数: 比如 `WHERE YEAR(order_date) = 2023` 这样会导致索引失效。应该写成 `WHERE order_date >= '20230101' AND order_date < '20240101'`。

2. SELECT vs. 明确字段:
永远不要用 `SELECT `! 尤其是在生产环境。
明确列出你需要的字段,这能减少网络传输的数据量,降低数据库的I/O负担,并且当表结构变化时,你的SQL不容易出错。
如果确实需要所有字段,请在开发或测试阶段使用,一旦确定需求,就改回明确列出。

3. JOIN 的选择:
INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL OUTER JOIN: 理解它们各自的含义和适用场景。
JOIN 的顺序: 数据库优化器通常会尝试找到最佳的 JOIN 顺序,但有时候你也可以通过调整 JOIN 的书写顺序,帮助优化器。通常先连接数据量小、过滤条件严格的表,能更早地减少中间结果集的大小。
避免笛卡尔积(CROSS JOIN): 除非你真的需要,否则没有 `ON` 条件的 `JOIN` 会产生所有行的组合,效率极低。

4. WHERE 子句优化:
“早过滤”原则: 尽量把过滤条件放在前面,这样能尽快缩小处理的数据范围。
避免使用 `OR` 连接大量条件: 有时 `OR` 会导致索引失效,可以考虑用 `UNION ALL` 来替代。
`LIKE` 的使用: `LIKE 'abc%'` 可以使用索引,但 `LIKE '%abc'` 或 `LIKE '%abc%'` 就很难走索引了(除非某些全文索引)。
`IN` vs. `EXISTS` vs. `JOIN`: 对于子查询,`IN`、`EXISTS` 和 `JOIN` 的性能表现可能不同,需要根据具体情况测试。通常 `JOIN` 的性能更好。

5. 聚合函数和 GROUP BY:
`COUNT(1)` vs. `COUNT()` vs. `COUNT(column)`: 在大多数现代数据库中,`COUNT(1)` 和 `COUNT()` 的性能几乎没有差别,都代表计算行数。`COUNT(column)` 会排除 NULL 值。
`HAVING` vs. `WHERE`: `WHERE` 子句在数据分组之前过滤,`HAVING` 子句在数据分组之后过滤。尽量将过滤条件放在 `WHERE` 里,这样可以减少分组时的计算量。

6. 了解查询执行计划(EXPLAIN/DESCRIBE):
这是性能优化的“核武器”。在 SQL 语句前加上 `EXPLAIN` (MySQL, PostgreSQL) 或 `DESCRIBE` (SQL Server),你可以看到数据库是如何执行你的 SQL 的:它会使用哪个索引?走了什么类型的 JOIN?是否进行了全表扫描?
通过分析执行计划,找出性能瓶颈,然后针对性地优化。

四、 避免常见陷阱和错误

1. 数据类型匹配: 比较时确保数据类型一致,否则可能导致隐式转换,影响性能或产生错误结果。例如,用字符串去匹配数字字段。
2. NULL 值处理: `NULL` 和任何值比较(包括 `NULL` 本身)结果都是 `UNKNOWN`,不会返回 TRUE。所以要用 `IS NULL` 或 `IS NOT NULL` 来判断 NULL。
3. 重复数据: 如果可能产生重复数据,记得使用 `DISTINCT` 或者 `GROUP BY`。
4. 事务的正确使用: 对于需要保证数据一致性的操作,务必使用事务 (`BEGIN TRANSACTION`, `COMMIT`, `ROLLBACK`)。
5. SQL 注入: 这是最危险的漏洞之一。永远不要直接将用户输入拼接到 SQL 语句中,而是使用参数化查询(Prepared Statements)。

五、 持续学习和实践

阅读优秀的代码: 多看看别人写的、被广泛使用的 SQL 语句。
参与代码评审: 互相学习,发现问题。
关注数据库的更新和新特性: 数据库的技术也在不断发展。
多动手实践: 理论再多,不如自己动手写几遍、改几遍。

总结一下,写出高质量的SQL语句,就像是一位优秀的厨师,需要:

了解食材(数据和表结构)。
掌握火候(数据库性能和执行计划)。
遵循菜谱(SQL语法和最佳实践)。
注重摆盘(代码的可读性和规范性)。
不断创新和学习(持续优化和新技术的应用)。

一开始可能觉得有点难,但只要你每次写SQL时都多花一点心思,考虑一下“能不能写得更清晰”、“能不能跑得更快”、“会不会有潜在问题”,久而久之,你的SQL就会越来越“漂亮”,越来越“有用”。祝你写出让大家都点赞的SQL!

网友意见

user avatar

阿里工程师分享9个自己写SQL的好习惯。亲身实践所得,欢迎讨论交流。


【点击头像关注我们知乎号,别错过更多阿里工程师一线技术干货。】

——————————————————————————————————————


1、查询中尽量避免使用SELECT * 以及加上LIMIT限制

当服务器响应客户端请求时,客户端必须完整的接收整个返回结果,而不能简单的只取前面几条结果,然后让服务器停止发送。查询应尽可能只返回必要数据,减小通信数据包大小和数量,提高效率。


2、IN 和 NOT IN 要慎用,会导致全表扫描。



上面例子使用 IN 时可以用到索引,使用 NOT IN 时未使用索引。


上面例子使用 IN 时未使用索引。


MySQL优化器会选择代价最小的方式执行,IN和NOT IN 都可能索引失效,不是绝对的。


3、LIKE 导致全表扫描


LIKE导致索引失效是因为没遵循最佳左前缀法则。字符串B-Tree排序方式:先按照第一个字母排序,如果第一个字母相同,就按照第二个字母排序,以此类推。

%号放右边
由于B-Tree的索引顺序,是按照首字母的大小进行排序,前缀匹配又是匹配首字母。所以可以在B+树上进行有序的查找,查找首字母符合要求的数据。所以有些时候可以用到索引。


4、联合索引需遵循最佳左前缀法则


GLS_CODE,BARCODE,SKU_ID 创建了联合索引,当查询语句where条件中没有GLS_CODE列不会走联合索引。创建这种多列联合索引时,列的顺序非常重要。


B-Tree联合索引组合顺序与创建时列的顺序是一样的,第一个字段列的顺序是确定的,其他列的顺序都是不确定的。B-Tree索引的限制,如果查询不是按照索引创建时的顺序,则无法使用索引。


在查询中where条件里存在联合索引第一列,顺序不一致也是可以走索引的。这里是因为MySQL优化器会对查询重新排序。


5、不要在索引列上做任何操作


索引列存在计算、函数、类型转换,会导致索引失效进行全表扫描。


6、is null,is not null可能导致索引失效


7、要注意where,order by,group by后面的列,多表关联的列是否已加索引,优先考虑组合索引


添加索引


8、where后面的列要注意隐式转换,会导致索引失效


不加单引号时,是字符串跟数字的比较,它们类型不匹配,MySQL会做隐式的类型转换,把它们转换为浮点数再做比较,最后导致索引失效。


9、count(*) 和 count(1) 的误解


dev.mysql.com/doc/refma
count(*) 和 count(1) 效率是完全一样的,并没有count(1)会比count(*)快的说法。


(本篇作者:阿里巴巴天猫奢品运营中心 乂嵘)

——————————————————————————————————————————

阿里巴巴集团淘系技术部官方账号。淘系技术部是阿里巴巴新零售技术的王牌军,支撑淘宝、天猫核心电商以及淘宝直播、闲鱼、躺平、阿里汽车、阿里房产等创新业务,服务9亿用户,赋能各行业1000万商家。我们打造了全球领先的线上新零售技术平台,并作为核心技术团队保障了11次双十一购物狂欢节的成功。详情可查看我们官网:阿里巴巴淘系技术部官方网站

点击下方主页关注我们,你将收获更多来自阿里一线工程师的技术实战技巧&成长经历心得。另,不定期更新最新岗位招聘信息和简历内推通道,欢迎各位以最短路径加入我们。

类似的话题

  • 回答
    好的,咱们这就来聊聊怎么才能写出那些读起来顺畅、跑起来飞快、维护起来省心的SQL语句,保证你说出来的时候,同事们都会眼前一亮,甚至有点小崇拜。这事儿说起来,可不是东拼西凑几条命令就行,里面门道可多着呢。一、 理解你的“敌人”:数据库和数据在提笔写SQL之前,最最重要的一步,就是要透彻理解你要打交道的.............
  • 回答
    政府部门的写材料高人,绝非一日练成,也非仅凭书籍就能达到。这更像是一场磨砺,一场与文字、与思想、与政策的深度对话。要成为其中的佼佼者,需要的是经验的积累、思维的训练、以及对现实的深刻洞察。首先,“输入”是基石。 所谓“读书破万卷,下笔如有神”,这话在政府写作领域尤为适用。但这里的“读”绝非泛泛而览,.............
  • 回答
    写出“Pythonic”的代码,就像是掌握一门语言的道地表达方式一样,它不仅仅是语法正确,更是遵循了这门语言的设计哲学,让你的代码读起来顺畅、高效,甚至带着点优雅。这就像你在跟一个懂 Python 的人聊天,你们的交流会非常自然流畅,而不是生硬的翻译。那么,到底怎么才能让你的 Python 代码“P.............
  • 回答
    要写出古文,并非易事,它牵涉到对古代汉语的深入理解,不单是遣词造句,更是文风、意境乃至思想的模仿。这绝非朝夕之功,需要耐心、毅力,更需要一份对古人智慧的敬畏。我且试着将我所知晓的,细致地与你道来。一、 奠定基础:筑牢根基,方能枝繁叶茂1. 博览群书,浸润古韵: 这是最最重要的一步。没有“读万卷书”.............
  • 回答
    想把文章写出鲁迅的“味道”,这可不是一件容易的事,它涉及到对鲁迅先生思想、文风、叙事方式的深刻理解和模仿,更需要一份真诚的“战士”般的笔触。这不像学习一道菜谱,跟着步骤就能做出来,更像是在体验一种人生,一种思考,然后用文字去倾诉。首先,咱们得明白,鲁迅先生的味道从何而来?1. 灵魂深处的忧患意识与呐.............
  • 回答
    让“高考争霸”拥有江湖气息,这绝非易事,因为“高考”本是现代教育的产物,与古老的“江湖”概念相去甚远。但我们可以巧妙地借用江湖的元素和意境,将一场严肃的学术竞争转化为一场充满张力与传奇色彩的“武林大会”。这就如同在现代都市中,要营造出古老寺庙的宁静与庄严,需要的是对细节的把控和对神韵的捕捉。我们要做.............
  • 回答
    写好留学文书,绝不是一篇流水账的个人介绍,它更像是一场与招生官的深度对话,通过文字让他们认识真实的你,并相信你就是他们正在寻找的那位学生。这需要策略、真诚和大量的思考。下面我就一点点拆解,说说怎么才能把这事儿办漂亮。第一步:理解文书的目的——你为什么要写它?别只想着“完成任务”,招生官读文书,是在寻.............
  • 回答
    你有一手好字,但还没被读者们发现?没关系,这世上从来不缺“酒香也怕巷子深”的故事,但更重要的是,好酒终会遇到懂它的人,而好的文字,同样如此。想靠写作为生,而且有那么点意思,咱们得聊聊怎么把这股子“有文采”的劲儿,变成实实在在的收入。别想着一夜成名,这事儿急不来,也玩不转。咱们先从最实在的入手,一点点.............
  • 回答
    坚持写作是一个既需要热情,也需要策略的过程。很多人都有写作的愿望,但往往难以持之以恒。以下是一些详细的方法,希望能帮助你克服困难,养成坚持写作的习惯: 第一阶段:建立写作的“意愿”和“动力”在开始行动之前,明确你为什么想写作至关重要。这份“为什么”将是你遭遇困难时强大的精神支柱。1. 找到你的“写.............
  • 回答
    熬过一天的脑力风暴,终于可以喘口气了。但你知道的,身体和精神都像是一团纠结在一起的毛线球,需要耐心梳理才能顺滑起来。别以为躺下刷手机就是休息,那多半是在给大脑增加新的“待办事项”。真正高效的休息,是让你明天能以更好的状态迎接新一天的挑战。第一步:物理上的“断离舍”在开始真正休息之前,先给自己一个物理.............
  • 回答
    写出荒诞却又令人捧腹的故事?这可不是件容易事,它需要一种超越常理的思维,一份对生活细微之处的敏锐观察,以及一颗敢于将它们拧巴在一起的心。当然,最重要的是,你得让读者在一开始就卸下防备,然后在你精心编织的“不合理”中,一点点陷进去,直到忍不住哈哈大笑。我们先不谈那些华而不实的大道理,直接来点实际的。想.............
  • 回答
    想写出引人入胜、让人拍案叫绝的好文章?这可不是一蹴而就的事,需要的是用心、耐心和一点点“秘诀”。别担心,我这就跟你聊聊,怎么才能让你的文字充满生命力,读起来就像是你的朋友在跟你讲故事、分享见解,而不是冰冷的机器在输出。第一步:灵魂的注入——你的想法和情感这篇文章之所以能打动人,首先是因为它有“你”的.............
  • 回答
    作为一名长年跟代码打交道的老兵,我深知在性能敏感的场景下,哪怕是微小的提升也可能带来质的区别。`memset` 和 `memcpy` 这两个函数看似简单,但它们在底层默默地为我们处理着大量的数据拷贝和填充工作。如果能对它们进行优化,让它们跑得更快,那绝对是一件令人兴奋的事。这篇文章,咱就来聊聊怎么把.............
  • 回答
    写出一份优秀的科研计划,就像是在为你的研究项目绘制一幅清晰、有说服力的蓝图。这份蓝图不仅要展现出你对研究课题的深刻理解,更要让审阅者相信,你具备完成这项研究的能力,并且这项研究具有重要的价值和可行性。下面,我将从多个角度,尽可能详细地为你拆解如何撰写一份优秀的科研计划,力求让它充满你的思考和热情,而.............
  • 回答
    好的,我们来聊聊如何构建一个经济学模型,让它既严谨又有生命力,而不是一篇冰冷的“AI制造”。写经济学模型,这事儿可不是凭空“写”出来的,更像是“构建”。它是一个逻辑严密的“故事”,用数学的语言讲述经济现象的内在联系和运行规律。你可以把它想象成一位侦探,面对复杂的案发现场(经济问题),需要收集线索(数.............
  • 回答
    小橘猫叫团团,最喜欢蜷在阳光洒满的地毯上打盹。有一天,它醒来,发现窗外飘落着白色的小羽毛,像雪花一样。团团好奇地伸出爪子,羽毛轻盈地落在它鼻尖上,痒痒的。它歪着头,用湿漉漉的黑眼睛看着,然后,轻轻地舔了一下鼻子,发出了满足的“呼噜呼噜”声。仿佛整个世界,都因为这片小小的羽毛而变得柔软可爱起来。.............
  • 回答
    他站在空荡荡的房间里,墙上挂着褪色的全家福。照片里的她笑容依旧灿烂,只是他再也无法听到她轻快的脚步声,再也闻不到她身上淡淡的皂角香。他摸了摸相框的边缘,那里留着她指尖留下的微凉。冬日的光线透过窗户,在地上拉出长长的影子,如同他此刻的心一样,空旷而沉重。手中的老旧收音机里,传来一首他们曾经最爱的歌,每.............
  • 回答
    他深吸一口气,准备在婚礼上向她告白,拆穿未婚夫的真面目。当他走上舞台,看到新娘时,却愣住了——她是他曾经深爱的,以为早已离世的青梅竹马。而坐在她身边的,是他多年未见的哥哥,两人正幸福地交换着戒指。他的告白卡在喉咙里,转身,消失在人群中。.............
  • 回答
    寒风凛冽,吹枯了黄叶,也吹不散萧瑟的剑意。客栈角落,他独酌一杯浊酒,刀疤划过嘴角,映着昏黄灯光,说不出的沧桑。门被猛地推开,一个身影踏入,衣袂猎猎,眼中寒光如刀,直取他的性命。“陆无名,今日便是你的死期!”来人厉喝,手中长剑颤鸣,剑尖指向他的咽喉。他缓缓放下酒杯,嘴角勾起一丝讥讽:“终于来了。”话音.............
  • 回答
    如果金庸大师笔下没有《三国演义》这层厚重的“滤镜”,他会如何挥洒笔墨,描绘那个群雄逐鹿、波澜壮阔的三国时代呢?我脑海中勾勒出的画面,绝非是依靠演义中那些已被无数次传颂的传奇人物和情节来填充,而是会从更广阔的历史背景和更细致的人性光辉中挖掘出独属于金庸式的武侠史诗。首先,人物的塑造会更加“草根”和“写.............

本站所有内容均为互联网搜索引擎提供的公开搜索信息,本站不存储任何数据与内容,任何内容与数据均与本站无关,如有需要请联系相关搜索引擎包括但不限于百度google,bing,sogou

© 2025 tinynews.org All Rights Reserved. 百科问答小站 版权所有