PostgreSQL的查询技巧: 零除, GENERATED STORED, COUNT DISTINCT, JOIN和数组LIKE
零除的处理
用NULLIF(col, 0)可以避免复杂的WHEN...CASE判断, 例如
ROUND(COUNT(view_50.amount_in)::NUMERIC / NULLIF(COUNT(view_50.amount_out)::NUMERIC, 0),2) AS out_divide_in,
使用 COLA / NULLIF(COLB,0) 后, 如果 COLB 为0, 产生的输出就是 NULL
GENERATED 字段, GENERATED..STORED
对于读多写少的表, 这是一个高效的性能提升方法, 对已知表可以增加Generated字段, 这些字段只读, 自动计算赋值, 可以像普通字段一样参与查询, 不需要在查询中实时计算, 是一种典型的使用空间换时间的优化方式.
ALTER TABLE "bank_card"
ADD COLUMN "card_num_in" varchar(255) GENERATED ALWAYS AS (CASE WHEN direction = 'IN' THEN card_num ELSE NULL END) STORED,
ADD COLUMN "card_num_out" varchar(255) GENERATED ALWAYS AS (CASE WHEN direction = 'OUT' THEN card_num ELSE NULL END) STORED,
ADD COLUMN "amount_in" numeric(53,2) GENERATED ALWAYS AS (CASE WHEN direction = 'IN' THEN amount ELSE NULL END) STORED,
ADD COLUMN "amount_out" numeric(53,2) GENERATED ALWAYS AS (CASE WHEN direction = 'OUT' THEN amount ELSE NULL END) STORED;
注意
- PostgreSQL 14 只有 STORED 类型的字段, 还不能使用 VIRTUAL 类型
- 这样的字段是只读的, INSERT 的时候不能往这些字段写入
- GENERATED 字段不带索引, 如果基于带索引的字段创建 GENERATED 字段, 在 GENERATED 字段上检索, 性能可能反而更差, 可以通过给 GENERATED 字段建索引解决.
COUNT DISTINCT 优化
COUNT DISTINCT 的性能问题
COUNT DISTINCT 的性能是PostgreSQL中长期存在的问题, 在版本14中尚未解决. 在数据量大的时候, 这个查询会很慢, 千万级别的表可能需要10秒左右才能返回结果
SELECT
COUNT(DISTINCT field_1)
FROM
table_1
原因链接
count(distinct ...) always sorts, rather than using a hash, to do its work. I don't think that there is any fundamental reason that it could not be changed to allow it to use hashing, it just hasn't been done yet. It is complicated by the fact that you can have multiple count() expressions in the same query which demand sorting/grouping on different columns.
PostgreSQL 的 count(distinct ...) 的实现方式是排序而不是使用 hash, 所以速度很慢. 应该要换成 hash 方式, 只是因为各种原因还没有实现.
规避途径一: 通过 COUNT 子查询
使用下面的方式, 查询时间能缩短一半以上
SELECT
COUNT(col)
FROM (
SELECT DISTINCT field_1 AS col FROM table_1
) TEMP
规避途径二: 通过 COUNT_DISTINCT 扩展
针对这个性能问题的扩展 count_distinct, 安装之后可以使用COUNT_DISTINCT()函数代替COUNT(DISTINCT ...), 但是缺点是费内存, 而且对参数有长度限制.
规避途径三: 通过 GROUP BY
使用GROUP BY代替DISTINCT, 下面的例子, 对 field_1 和 field_2 建联合索引, 速度会非常快
SELECT COUNT(field_2), field_1, field_2
FROM table_1
GROUP BY field_1, field_2
对于复杂场景, 可以对 GROUP BY 之后的结果建立视图, 而后以子查询的形式取值
优化JOIN性能
JOIN查询, 需要限定JOIN的范围, 例如对于一个翻页查询, 需要对翻页的结果通过JOIN挂接大量属性的, 翻页结果通过LEFT JOIN连接到多个属性表, 就应该将翻页结果限制数量后, 再进行关联, 这样性能会好很多, 例如
Preparing : SELECT
"view_46"."id",
"view_46"."name",
"label_view6"."labels" AS "1___label",
"label_view7"."labels" AS "21022___label",
"label_view8"."labels" AS "21023___label",
"label_view9"."labels" AS "50197___label"
FROM
-- 这行是关键, 因为主体在ID上有索引, 偏移查询是很快的, 先限制结果集大小, 然后再进行JOIN
( SELECT * FROM "view_46" ORDER BY ID ASC LIMIT 10 OFFSET 14270 ) AS "view_46"
LEFT JOIN "label_view" AS "label_view6" ON (
"label_view6"."item_type" = '1'
AND "label_view6"."item_name" = '1'
AND "label_view6"."item_attr" = '2'
AND "label_view6"."item_id" = "view_46"."id" :: TEXT
)
LEFT JOIN "label_view" AS "label_view7" ON (
"label_view7"."item_type" = '1'
AND "label_view7"."item_name" = '21022'
AND "label_view7"."item_attr" = '2'
AND "label_view7"."item_id" = "view_46"."id" :: TEXT
)
LEFT JOIN "label_view" AS "label_view8" ON (
"label_view8"."item_type" = '1'
AND "label_view8"."item_name" = '21023'
AND "label_view8"."item_attr" = '2'
AND "label_view8"."item_id" = "view_46"."id" :: TEXT
)
LEFT JOIN "label_view" AS "label_view9" ON (
"label_view9"."item_type" = '1'
AND "label_view9"."item_name" = '50197'
AND "label_view9"."item_attr" = '2'
AND "label_view9"."item_id" = "view_46"."id" :: TEXT
)
ORDER BY
ID ASC
LIKE ARRAY的用法
PostgreSQl 的LIKE用法
LIKE
LIKENOT LIKELIKE ANY(ARRAY[])如果需要相似任意一个参数, 需要使用这个语法NOT LIKE ALL(ARRAY[])如果想达到不相似任意一个参数, 需要用这个语法
ILIKE
ILIKE是不区分大小写的LIKE
ILIKENOT ILIKEILIKE ANY(ARRAY[])NOT ILIKE ALL(ARRAY[])
PostgreSQL的查询技巧: 零除, GENERATED STORED, COUNT DISTINCT, JOIN和数组LIKE的更多相关文章
- SQL高级查询技巧
SQL高级查询技巧 1.UNION,EXCEPT,INTERSECT运算符 A,UNION 运算符 UNION 运算符通过组合其他两个结果表(例如 TABLE1 和 TABLE2)并消去表中任何重 ...
- PostgreSQL LIKE 查询效率提升实验<转>
一.未做索引的查询效率 作为对比,先对未索引的查询做测试 EXPLAIN ANALYZE select * from gallery_map where author = '曹志耘'; QUERY P ...
- 【转】sql各种查询技巧
高级查询在数据库中用得是最频繁的,也是应用最广泛的. Ø 基本常用查询 --select select * from student; --all 查询所有 select all sex from ...
- [MySQL]子语句的查询技巧
一.统计group by语句的行数 group by语句中,如果包含字段统计函数(诸如:count(),sum()...),这种情况下统计函数只会作用于group by的字段,因此想拿到最终结果的行数 ...
- 各种SQL查询技巧汇总 (转)
原文地址: https://blog.csdn.net/tim_phper/article/details/54963828 select select * from student; all 查询所 ...
- sql各种查询技巧
SQL Server T-SQL高级查询 高级查询在数据库中用得是最频繁的,也是应用最广泛的. Ø 基本常用查询 --select select * from student; --all 查询所有 ...
- Mapper查询技巧
Sql字段动态比较判断 <sql id="getUserInfoList_body"> SELECT * from userinfo <dynamic prepe ...
- hive的高级查询(group by、 order by、 join 、 distribute by、sort by、 clusrer by、 union all等)
查询操作 group by. order by. join . distribute by. sort by. clusrer by. union all 底层的实现 mapreduce 常见的聚合操 ...
- 使用子查询可提升 COUNT DISTINCT 速度 50 倍
注:这些技术是通用的,只不过我们选择使用Postgres的语法.使用独特的pgAdminIII生成解释图形. 很有用,但太慢 Count distinct是SQL分析时的祸根,因此它是我第一篇博客的不 ...
随机推荐
- Mybaitis入门基础(一)MyBatis的概念引入及工作原理
阅读目录 一:对原生态JDBC问题的总结 二:MyBatis框架 三:mybatis入门程序 四:mybatis和Hibernate的本质区别与应用场景 五:小结 一:框架前言的那些事 良将难求 胜铁 ...
- Java 8的18个常用日期处理
Java 8的18个常用日期处理 一.简介 伴随 lambda表达式.streams 以及一系列小优化,Java 8 推出了全新的日期时间API. Java处理日期.日历和时间的不足之处:将 java ...
- jmeter工具初探
jmeter工具初探 一.jmeter工具介绍 1.一种免费的java开源工具,可以进行二次开发 2.运行环境:java运行环境,需要安装JDK,配置JAVAHOME 环境变量 3.下载jmeter: ...
- 攻防世界-MISC:Erik-Baleog-and-Olaf
这是攻防世界MISC高手进阶区的题目,题目如下 点击下载附件一,解压后得到一个文件,不知道是什么格式,用010editor打开,发现其为png文件,就把它的后缀改为png,然后用stegslove打开 ...
- ThinkPHP信息泄露
昨天遇到了一个ThinkPHP日志泄露,然后我就写了个脚本利用shodan搜索批量的来找一下漏洞,估计已经被人撸完了,不过还有一些网站有着此漏洞.ip收集和漏洞验证脚本工具我会放在最下面,需要的直接复 ...
- Linux的快捷使用(不断更新中)
Linux 命令行提示符 ~代表当前目录,即家目录,#是超级用户提示符,如果是普通用户使用$ 基本快捷键的使用 移动光标命令 Ctrl+A:移动光标到开头 Ctrl+E:移动光标到结尾 Ctrl+F: ...
- 基于 Jenkins + Kubernetes + Argo CD 的完整 DevOps 流程记录(1) - 环境部署
一.环境准备 1.1 镜像仓库 整套 DevOps 流程使用 Harbor 作为内部镜像仓库,所有构建产物(镜像)都会推送到 Harbor,以备后续进行项目部署.Harbor 从 2.x 版本开始支持 ...
- 118_Power Pivo周维度度同比、环比相关
博客:www.jiaopengzi.com 焦棚子的文章目录 请点击下载附件 一.背景 在群里看到有人在交流周维度同环比,同时又好多天都没有更新文章了,最近没有什么好的素材,就硬生生的写一个吧. 先来 ...
- 满满干货!手把手教你实现基于eTS的分布式计算器
最近收到很多小伙伴反馈,想基于扩展的TS语言(eTS)进行HarmonyOS应用开发,但是不知道代码该从何处写起,从0到1的过程让新手们抓狂. 本期我们将带来"分布式计算器"的开发 ...
- 20 HTTP 长连接与短连接
20 HTTP 长连接与短连接 每日一句 纸上得来终觉浅,绝知此事要躬行. 每日一句 Never give up until the fight is over. 永远不要放弃,要一直战斗到最后一秒. ...