sql 优化 具体案例分析-基于pgsql数据库

我们来对sql是否使用索引来进行分析, 要用到的sql语句如下:

explain (ANALYZE on ,TIMING on, VERBOSE on, BUFFERS on, COSTS on ) select cons_name from c_cons where cons_name like '45%'

explain (ANALYZE on ,TIMING on, VERBOSE on, BUFFERS on, COSTS on ) select * from e_mp_day_read where data_date  <> '2020-06-30 00:00:00'

explain (ANALYZE on ,TIMING on, VERBOSE on, BUFFERS on, COSTS on ) select * from e_mp_day_read where data_date  in ('2020-06-30 00:00:00')

explain (ANALYZE on ,TIMING on, VERBOSE on, BUFFERS on, COSTS on ) select * from e_mp_day_read where data_date  = '2020-06-30 00:00:00'

explain (ANALYZE on ,TIMING on, VERBOSE on, BUFFERS on, COSTS on ) select * from e_mp_day_read where data_date  not in ('2020-06-30 00:00:00')

第一条语句:

解析: 对于c_cons表 , cons_name是建立了索引的 。 但是对于like 来说, 模糊表达式% 在‘45’后面,按照规则是应该走索引的,但是实际执行缺没有走索引。 这是为什么?

个人猜测: pgsql在实际执行前,会有一次预估执行, 对于数据量小的列做where时, 使用全表扫描比索引扫描效率更高。 所以pgsql选择了全表扫描的方式,而没有使用cons_name的索引。

为什么数据量少的时候全表扫描的效率会更高呢? 因为基于全表扫描,只需要按行数对列进行读取。 而基于索引扫描,需要执行两次I/O操作。 读取索引一次I/O, 读取 数据列一次I/O。

第二条语句执行情况分析:

这条语句中, e_mp_day_read中的data_date建立了索引字段。但在实际执行的情况中,很明显sql执行规划中没有使用索引。 为什么呢? 很明显,是 where 的 <> 操作符是data_date列的索引失效了。

可以看到他是基于全表扫描, 查询时间是1.172秒, 注意, 此时数据库中有10000条数据。

第三条语句执行情况分析:

这里where对于data_date使用了in关键字, 可以看到,执行规划中使用了索引扫描。 查询时间达到了  0.018秒, 在同是10000条数据的情况下, 使用索引要比全表扫描快65倍左右!

我们在看看使用not in关键字的情况:

可以看到, not in关键字是列索引失效了。 查询时间高达1.212秒。

我们再来看看最后一条sql 。 当日期类型 和 字符串格式的日期 作为条件进行查询是,索引是否失效?

可以看到, 索引没有失效。 具体分析, 看 index Cond 展示的信息, 和data_date字段进行比较的参数类型是 timestamp 。 也就是所, pgsql在对字符串格式的日期进行比较前, 先将字符串格式转成 了日期格式然后进行的比较。 正式比较时, 是两个日期格式在比较。所以索引有效。用时0.017秒。

这里简单的记录一下。 

一般来说。 使用  like '%a'   ,   not in  , <> , !=  , data_time(data_time) , num = a*b  这些情况下, 索引会失效。

 

最后一个注意点:

我们对flag_input (varchar类型)加了索引,但是flag_input整个列的值加了 check 约束(约束内容是1或2), 所以flag_input的值不是1 ,就是2。

可以看到,flag_input的索引失效了。

为什么? 因为 当索引列的值包含大量重复数据时, 实际执行不会走索引, 而是全表扫描。

那么这种情况怎么解决?

现在的问题是flag_input不走索引, 这个不走索引不是因为我们sql 写的有问题,而是列的值太多重复造成的情况。 我们可以重新定义一个列, 叫 flag_input_copy 。 flag_input_copy = flag_input + UUID。

这样flag_input_copy的值就不会大量重复了。 对flag_input的查询可以换为对flag_input_copy的查询。 只需要 like  '(flag_input的值)%'  即可。

<think>好的,我需要帮助用户了解 PostgreSQL 数据库占用30GB内存的情况。首先,我得回忆一下PostgreSQL的内存管理机制。PostgreSQL使用共享内存和私有内存,共享内存包括shared_buffers等,而私有内存则用于每个连接的查询处理。 用户提到30G内存占用,这可能包括多个部分。首先,shared_buffers通常建议设置为总内存的25%-40%,如果总内存较大,比如64G,那么shared_buffers可能在16G到25G之间。如果用户设置过高,可能导致占用较多内存。 然后,work_mem是每个排序或哈希操作使用的内存。如果有多个并发查询,每个查询可能分配多个work_mem,比如100个连接,每个需要4MB的话,总共有400MB。但如果设置过高或查询复杂,可能占用更多。 还有maintenance_work_mem用于维护任务,比如VACUUM或创建索引。如果进行大量维护操作,这部分内存也会增加。 此外,操作系统缓存也会占用内存,但PostgreSQL本身可能不会主动释放,这可能导致总内存占用看起来很高。需要确认用户是否将操作系统缓存也算在内。 还需要考虑是否有内存泄漏,或者配置参数设置不当。比如,shared_buffers设置过高,或者work_mem分配太大,导致内存被迅速消耗。 用户可能需要检查postgresql.conf中的参数,如shared_buffers、work_mem、maintenance_work_mem,以及max_connections。此外,使用pg_top或系统监控工具查看内存使用情况,确定哪些进程或组件占用了最多的内存。 另外,如果数据库有大量活跃连接,每个连接的私有内存累积起来也可能占用较大空间。建议优化连接池,使用连接池工具如pgBouncer来减少连接数。 最后,需要确认是否真的存在性能问题,因为合理的内存使用可以提高性能,但如果导致系统交换(swapping),就需要调整参数。建议用户根据实际负载调整参数,并监控内存使用情况。</think>PostgreSQL 占用 30GB 内存的典型场景及分析框架如下: $$ \text{总内存占用} = \text{共享内存} + \sum(\text{私有内存}) + \text{操作系统缓存} $$ 1. **共享内存区** 核心参数: $$ \text{shared\_buffers} \times \text{block\_size} $$ 典型值: - 默认 128MB - 生产环境建议设为物理内存的 25%-40% - 若设置为 8GB,则占内存总量 26.7%(按 30GB 总占用量计) 2. **私有内存区** - *work_mem*: $$ \text{单查询内存} = \text{work\_mem} \times \text{排序/哈希操作次数} $$ 假设设置 4MB,100 个并发查询可能占用: $$ 100 \times 4MB \times 3 = 1.2GB $$ - *maintenance_work_mem*: 自动 vacuum 时可能占用: $$ \text{典型值 1GB} \times \text{并行 workers} $$ 3. **内存黑洞** - 查询计划缓存(>= PG12) - 扩展插件内存分配(如 PostGIS、pg_stat_statements) - 连接池内存: $$ \text{总连接数} \times 2MB \sim 10MB $$ 4. **诊断工具** ```sql -- 查看共享内存分配 SELECT name, setting || ' B' AS size FROM pg_settings WHERE name IN ('shared_buffers','huge_pages','temp_buffers'); -- 检查会话内存使用 SELECT pid, query, pg_size_pretty(pg_session_ram(pid)) FROM pg_stat_activity; ``` 5. **优化路径** 黄金分割比例建议: $$ \frac{\text{shared\_buffers}}{\text{总内存}} \in [0.25, 0.4] $$ $$ \frac{\text{work\_mem}}{\text{总内存}} \leq \frac{0.1}{\text{最大并发数}} $$ 案例:某 64GB 服务器优化方案 ```ini shared_buffers = 24GB work_mem = 128MB # 按最大 80 并发设计 maintenance_work_mem = 2GB effective_cache_size = 48GB max_connections = 200 # 配合 pgBouncer 使用 ``` 建议通过 `EXPLAIN ANALYZE` 分析具体查询的内存消耗模式,配合 `pg_controldata` 检查实际内存分配情况。当内存使用达到物理内存的 70% 时需警惕 OOM 风险。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值