PostgreSQL 语句调优

本文分享了PostgreSQL数据库中SQL语句调优的实用技巧,包括避免全表扫描、使用具体字段列表代替*、优化LIKE语句、避免对NULL判断、避免使用!=或<>、避免使用OR、避免使用NOT IN或IN、使用EXISTS代替IN、避免在条件左侧使用算法、避免使用DISTINCT和ORDER BY、GROUP BY和HAVING优化、JOIN类型选择、UNION与UNION ALL对比、批处理更新等。

PostgreSQL 语句调优-Sql语句优化


作为一名优秀的码农,对于了解Sql如何调优是很有必要的。。简单总结一下,
	
	1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引(单表索引不能超过六个)
	2.使用更多的条件,缩小查找范围
	3.使用关联时,用小结果集驱动大结果集

(ps:下面的语句推荐给司机们,赶快上车)
--EXPLAIN:表示打出某sql的执行计划,看看是否走了全表,ANALYZE: 表示需要消耗的时间耗时,
EXPLAIN ANALYZE SELECT id,a FROM A; 

下面是我日常用到的一些Sql优化点,大家可以借鉴一下

1. 查询字段优化 千万不要使用 SELECT * 用具体的字段列表替换 * ,不要返回用不到的字段

返回了不必有的数据,就会浪费内存,加重网络的负担降低性能 。如果表大,在表扫描的期间将表锁住,禁止其他的链接访问表,后果严重!!

--correct SQL
SELECT * FROM A; 
--error SQL
SELECT id FROM A WHERE create_time >'2019-1-1';
2. where子句 like调优

若在关键词abc前面用了“%”,会导致该Sql走全表查询,除非必要,否则不要在关键词前加%
ps: 查询耗时和字段值总长度成正比

--error SQL 
SELECT id FROM A WHERE name LIKE '%abc%';
--correct SQL
SELECT id FROM A WHERE name LIKE 'abc%';
3. where子句 避免对null做判断

该判断将导致引擎放弃使用索引而进行全表扫描,建议针对null字段设置默认值0

--error SQL 
SELECT id FROM A WHERE a ISNULL;
SELECT id FROM A WHERE a NOTNULL;
--correct SQL 可以在a上设置默认值0,确保表中a列没有null值
SELECT id FROM A WHERE a =0;
SELECT id FROM A WHERE a >0;
4. where子句 避免使用 != 或者 <>

该判断将导致引擎放弃使用索引而进行全表扫描,建议将不等于 拆成 大于或者小于

--error SQL 
SELECT id FROM A WHERE a !=2017;
--correct SQL 
SELECT id FROM A WHERE a >2017 OR a <2017;
5. where子句 避免使用 or

使用or的子句可以分解成多个查询,并且通过union链接多个查询。它们的速度只同是否使用索引有关,如果查询使用到联合索引,用unionAll执行的效率更高,多个or字段的字句没有用到索引,改写成union的形式,再视图与索引匹配

--error SQL 
SELECT id FROM A WHERE a >2017 OR a <2017;
--correct SQL 
SELECT id FROM A WHERE a >2017
UNION ALL
SELECT id FROM A WHERE a <2017;
6. where子句 避免使用 NOT IN 或者 IN

NOT IN sql执行时,会转成 <> 将导致引擎放弃使用索引而进行全表扫描,不推荐使用NOT IN
IN 也会使系统无法使用索引,而只能直接搜索表中的数据(ps:如果一定要使用in 注意在in后面值的列表中,将出现最频繁的值放在最前面,出现的最少的放在最后面,减少判断的次数)

--error SQL 
SELECT id FROM A WHERE a IN (2017,2018,2019);
SELECT id FROM A WHERE a IN (SELECT id FROM B);
--correct SQL  如果查询的是连续的值,可以使用BETWEEN AND 函数
SELECT id FROM A WHERE a BETWEEN 2017 AND 2019
--correct SQL  如果只是IN中的子表结果集比较大,建议使用 EXISTS
SELECT id FROM A WHERE EXISTS (SELECT 1 FROM B WHERE B.id=a)
7. where子句 EXISTS 和 IN 的使用方式

IN 是在内存中比较的,只执行一次,把B表中的所有id字段缓存起来,之后检查A表的id是否与B表中的id相等,如果id相等则将A表的记录加入到结果集中,直到遍历完A表的所有记录
EXISTS 需要查询数据库,所以当B的数据量比较大时,EXISTS效率优于IN

--error SQL  
SELECT id FROM A WHERE a IN (SELECT id FROM B);
--correct SQL  
SELECT id FROM A WHERE EXISTS (SELECT 1 FROM B WHERE B.id=a)
--correct SQL  如果只是IN子表查询结果,建议使用 EXISTS
SELECT id FROM A WHERE EXISTS (SELECT 1 FROM B WHERE B.id=a)
8. where子句 避免在条件左侧使用算法

在where子句中的“=”左边进行函数、算数运算或其他表达式运算,系统可能无法正确的使用索引

--error SQL 
SELECT * FROM A WHERE a/2=100;
SELECT * FROM A WHERE SUBSTRING(a,1,4)=’6666’;
--correct SQL  
SELECT * FROM A WHERE a=100*2;
SELECT * FROM A WHERE a LIKE ’6666%’;
9. 避免使用 DISTINCT 和 ORDER BY

它会使查询变慢,这些动作可以改在客户端执行也可以

10. GROUP BY 和 HAVING 的优化

如果能在group by的having字句之前就能剔除多余的行,所以尽量不要用他们来做剔除行的动作。最优执行顺序:select 的where字句选择所有合适的行,group用来分组统计,having用于剔除多余的分组。这样group by和having的开销小,查询快。对于大的数据进行分组和having十分消耗资源。如果group by的目的不包括计算,只是分组。Distinct更快

11. INNER JOIN 比 LEFT JOIN和RIGHT JOIN快

因为inner join是等值连接,或许返回的行数比较少.提倡使用内联INNER JOIN

12. UNION ALL 比 UNION 快

UNION在进行表链接后会筛选掉重复的记录,UNION ALL不会去除重复记录
UNION将会按照字段的顺序进行排序,UNION ALL只是简单的将两个结果合并后就返回

13. 一次更新多条记录比分多次更新每次一条快

意思就是使用批处理更有效率

--error SQL 
INSERT INTO A(id,a) VALUES (1,10);
INSERT INTO A(id,a) VALUES (2,16);
--correct SQL  
INSERT INTO A(id,a) VALUES (1,10),(2,16);

<think>首先,用户的问题是:“我想优化SQL查询性能 请问SQL语句性能技巧”。我需要基于系统指令和提供的引用来回答。 系统指令: - 所有行内数学表达式必须使用$...$格式。 - 独立公式使用$$...$$。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识。 - 结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠。 提供的引用: - [^1]: SQL技巧,包括解析和执行阶段,减少解析或执行时间。 - [^2]: SQL指南,包括数据库配置优化如内存分配、磁盘I/O优化。 - [^3]: SQL语句优化的30种方法,例如避免在where子句中使用参数导致全表扫描。 - [^4]: SQL性能优化15个小技巧,如选择字段类型的原则。 回答结构: 1. **引言**:简要介绍SQL性能的重要性。 2. **逐步技巧**:列出并解释关键技巧,参考引用内容。 3. **引用标识**:在引用段落末尾添加[^n]。 4. **相关问题**:在结尾生成相关问题。 关键技巧(基于引用): - 减少解析和执行时间([^1])。 - 数据库配置优化:内存分配(如innodb_buffer_pool_size),磁盘I/O优化(如RAID 10)([^2])。 - SQL语句优化:避免在where子句中使用参数(会导致全表扫描),使用索引([^3])。 - 字段类型选择:用数字类型代替字符串,使用小的类型,固定长度用char,变长用varchar,金额用decimal([^4])。 其他常见技巧(基于知识): - 使用索引优化查询。 - 避免SELECT *,只选择需要的列。 - 优化JOIN操作。 - 使用EXPLAIN分析查询计划。 - 避免嵌套查询。 - 定期更新统计信息。 步骤: 1. 分析问题:解释为什么需要。 2. 提供技巧:分点列出,每个点解释并引用。 3. 总结。 4. 生成相关问题。 生成相关问题: - 基于主题,如如何分析慢查询、索引优化技巧等。 最终输出格式: - 使用中文。 - 行内数学表达式用$...$(如果有)。 - 独立公式用$$...$$(如果有)。 - 添加引用标识。 - 结尾添加相关问题。</think>### SQL语句性能技巧 优化SQL查询性能是提升数据库应用效率的关键。通过减少SQL解析和执行时间、优化数据库配置和改进SQL编写方式,您可以显著提升查询速度。以下我将基于可靠实践和引用内容,逐步介绍核心技巧。技巧按“分析-优化-验证”流程组织,帮助您系统性地解决问题。注意:应在SQL功能正确后再进行,以避免引入错误[^1]。 #### 1. **分析查询瓶颈(诊断阶段)** - **使用`EXPLAIN`命令**:在SQL前添加`EXPLAIN`(如MySQL或PostgreSQL),查看执行计划。这能揭示是否使用了索引、是否全表扫描等关键信息。例如: ```sql EXPLAIN SELECT * FROM orders WHERE customer_id = 100; ``` 输出结果中,若“type”列为“ALL”,表示全表扫描,需优化索引[^3]。 - **监控慢查询日志**:启用数据库的慢查询日志(如MySQL的`slow_query_log`),记录执行时间超过阈值的SQL,便于定位问题[^2]。 #### 2. **优化SQL编写(核心技巧)** 改进SQL语句本身是最高效的方式,参考以下原则: - **避免全表扫描**: - 在`WHERE`子句中,先使用索引列,并避免参数化查询(如`@num`),因为运行时解析变量可能导致全表扫描。例如: ```sql -- 不推荐:使用变量导致全表扫描 SELECT id FROM t WHERE num = @num; -- 推荐:直接使用常量或预编译参数 SELECT id FROM t WHERE num = 100; ``` 这能减少解析开销[^3]。 - 确保索引有效:在经常查询的列上创建索引(如`CREATE INDEX idx_name ON table(column)`),但避免过度索引(影响写入性能)。 - **精简查询字段**: - 用`SELECT column1, column2`代替`SELECT *`,只获取必要数据,减少数据传输量[^4]。 - 字段类型优化: - 先使用数字类型(如`INT`)而非字符串(如`VARCHAR`),因为数字处理更快。 - 固定长度字符串用`CHAR`,变长用`VARCHAR`;金额用`DECIMAL`避免精度损失[^4]。 - 例如:布尔值用`BIT`,枚举值用`TINYINT`。 - **优化JOIN和子查询**: - 用`JOIN`替代嵌套子查询,减少临时表创建。 ```sql -- 不推荐:嵌套子查询 SELECT * FROM orders WHERE customer_id IN (SELECT id FROM customers WHERE status = 'active'); -- 推荐:使用JOIN SELECT orders.* FROM orders JOIN customers ON orders.customer_id = customers.id WHERE customers.status = 'active'; ``` - 确保JOIN列有索引,避免笛卡尔积。 - **减少解析开销**: - 使用预编译语句(如参数化查询),避免每次执行都重新解析SQL。例如在Java中使用`PreparedStatement`[^1]。 #### 3. **数据库配置优化(系统级整)** 针对数据库环境进行,提升整体性能: - **内存分配**: - 整缓冲池大小(如MySQL的`innodb_buffer_pool_size`),增加内存缓存,减少磁盘I/O。一般设置为系统内存的70-80%[^2]。 - 公式:$$ \text{缓冲池大小} = \text{总内存} \times 0.7 $$,确保常用数据驻留内存。 - **磁盘I/O优化**: - 使用高性能磁盘(如RAID 10阵列),并分离数据文件和日志文件到不同磁盘,减少争用。 - 整日志写入频率(如MySQL的`innodb_flush_log_at_trx_commit`),平衡安全性和性能[^2]。 - **并发控制**: - 设置合理的事务隔离级别(如`READ COMMITTED`),避免锁竞争。 #### 4. **验证与监控(持续改进)** - **测试性能**:使用工具(如`sysbench`)模拟负载,对比优化前后查询时间。 - **定期维护**: - 更新统计信息(如`ANALYZE TABLE`),帮助优化器选择最佳执行计划。 - 重建碎片化索引(如`OPTIMIZE TABLE`)。 - 后,监控数据库指标(如CPU、I/O使用率),确保优化有效[^1][^2]。 #### 总结 SQL性能需结合语句优化和系统配置:先精简SQL、利用索引,再整内存和I/O。实践中,80%的性能问题源于SQL编写不当[^3]。始终在功能正确后,并测试回归。如果您提供具体SQL或数据库类型(如MySQL/Oracle),我可给出更针对性建议。
评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值