世界快报:【数据库学习】数据库平台:postgresql安装配置与常见命令
1,概念
2,安装配置与常见命令
【资料图】
1)安装与配置
#安装yum install https:....rpm
1>安装目录
bin目录:二进制可执行文件目录,此目录下有postgres、psql等可执行程序;pg_ctl工具在此目录,可以通过pg_ctl --help查看具体使用。conf目录:emptyinclude:头文件目录lib:动态库目录,如libpq.soshare:存放文档和配置模板文件,一些扩展包的sql文件在子目录extension下。
2>数据目录
/var/lib/pgsql//data。
i>pg_hba.conf(认证配置文件)
用于配置数据库的远程连接,通过加入以下命令行,运行任何用户远程连接本数据库,连接时需要提供密码。
host replication all 127.0.0.1/32 md5host replication all 10.99.99.99 md5 # ip为10.99.99.99机器可访问host all all 0.0.0.0/0 md5 # navicat可访问。md5表示要求客户端提供一个 MD5 加密的口令进行认证。如果改为trust表示无条件地允许联接。
ii>postgresql.conf(主配置文件)
所有配置信息在系统视图pg_settings中可查看,通过context可知修改相关配置后是否需要重启。
internal 只读参数,初始化实例时写死的。postmaster 改变后需要重启。sighup/backend 不需要重启,需要向postmaster主进程发送SIGHUP信号,让其重启装配配置新的参数。运行pg_ctl reload命令重新装配。superuser 超级用户使用set命令改变。user 普通用户使用set命令改变。
## 连接配置项listen_addresses = "*" # 默认为localhost,这会导致远程主机无法登录数据库。写具体网络ip表示让特定机器登录,*表示所有地址都可监听。port = 5432 # pg默认端口为5432。多个pg实例可以设置不同端口。max_connections #允许数据库连接的最大并发连接数,默认100,修改后需要重启。通过sql:show max_connections;也可以查看superuser_reserved_connections #超级用户连接数。默认为3,为防止普通用户消费连接数过多导致超级用户无法连接pg。## 日志配置项logging_collector = on #开启日志收集。pgSQL10已经默认开启log_directory = "log" #日志目录。日志切换与覆盖有多种方案,可配。一是每天生成一个新的日志文件;二是日志写满到一定大小开启新文件;三是只保留最近7天日志,循环覆盖(pgSQL10默认模式)。## 内存配置项shared_buffers = 4096MB # min 128kB 共享内存大小,主要用于共享数据块。默认值为32MB,尽量设置大一些。具体说明见后文讲解。work_mem = 4MB # min 64kB 单个SQL执行、排序、Hash Join时使用的内存,执行完毕后释放。设置大一些会提高排序操作效率。具体说明见后文讲解。max_stack_depth #服务器执行堆栈的最大安全深度,默认为2M。如果发现不能运行复杂的函数时,可以调高此配置,但一个正在运行的递归函数可能会导致pg后台服务进程崩溃,慎重设置。
iii>其它文件
文件/目录作用备注
PG_VERSIONpg版本号
postmaster.opts记录服务器上次启动的命令行参数
base默认表空间的目录下面子目录以对应数据库的OID命名,对应OID子目录下存放着这个数据库的表、索引等数据文件。OID通过select oid,datname from pg_database;查询。
global一些共享系统表的目录
log程序日志目录pg10版本之前未pg_log目录
pg_commit_ts视图提交的时间戳数据pg9.5之后
pg_walWAL日志的目录,在pg10之前此目录是pg_clog
2)psql命令行操作
# 数据库连接: psql命令在postgresql/bin目录下。# 添加参数-E可以在执行psql快捷命令时同时输出对应sql。也可以通过命令\set ECHO_HIDDEN on|off控制psql "host=127.0.0.1 port=5432 user=postgres password=123456 dbname=postgres"psql -U postgres -d DB_NAME -h localhost -c "select * from user_info"# 数据导出-pg_dump命令pg_dump "host=XX.XX.XX.XX port=5432 user=XXXX password=XXXX dbname=XXXXX" -t table_name -f table_name.sql# 数据导出-psql命令psql "host=XX.XX.XX.XX port=5432 user=XXX password=XXX dbname=XXX" -f table_name.sql
常见psql快捷命令(通过psql连接数据库后,通过“\”开头的快捷命令进行数据库相关操作,tab键可补全命令):
说明命令备注
退出命令行模式\q
查看数据库\l小写L
切换数据库\c dbName
查询当前登录的数据库和用户\cYou are now connected to database “postgres” as user “postgres”
查看sql语法(help)\h create user
查看更多命令?
查看所有表\d
查看结构\d namename可以包含通配符*或?,可以是表名、索引、视图、序列、函数。如果使用\d+会显示的更详细
列出所有schema\dn
查看所有表空间\db
查看所有角色和用户\du或\dgpg中用户和角色是不区分的
查看表权限分配情况\dp或\z
查看执行时间\timing on sql语句
指定客户端字符编码\encoding gbkutf8
执行外部文件的sql命令\i fileName或 psql -x -f fileName
编辑器\e类似vi,退出vi后会执行其中输入的内容
查看或编辑函数\ef 函数名不加函数名显示函数模板。退出vi后可\reset来清除命令缓冲区数据,防止误操作。
查看或编辑视图\ev 视图名不加函数名显示视图模板。退出vi后可\reset来清除命令缓冲区数据,防止误操作。
3)查看版本信息
说明命令
查看客户端版本psql --version
查看服务器版本详细信息select version();
查看服务器版本信息show server_version;
查看服务器数字版本信息包括小版号SHOW server_version_num;
4)服务启停及原理
1>服务启动
直接运行postgres进程
/lwh/postgresql/bin/postgres -D /lwh/data/postgresql & #-D指定数据目录,&表示后台执行。postgres也可以换成postmaster,一回事。如果权限不够在命令前面添加:su postgres -c
使用pg_ctl命令启动
/lwh/postgresql/bin/pg_ctl start -D /lwh/data/postgresql #-D指定数据目录
2>服务停止
直接向运行的postgres主进程发送signal信号
signal信号关机模式描述
SIGTERMSmart Shutdown 智能关机服务器将不允许新连接,等所有连接断开才关闭数据库
SIGINTFast Shutdown 快速关机不再允许新连接,并向所有子进程发送 SIGINT 信号,让它们立刻退出,然后等待子进程退出后关闭数据库
SIGQUITImmediate Shutdown 立即关闭立即关闭并退出,下次启动时数据库重放WAL日志进行恢复。仅用于紧急情况的关闭。
使用pg_ctl命令停止数据库
#没有权限需要在最前面添加su postgres -cpg_ctl stop -D dataDir -m smart #对应Smart Shutdown 模式;fast对应 Fast Shutdown;immediate 对应 Immediate Shutdown.具体说明可通过--help查看。默认模式是哪个?谁知道啊???
3>服务检测是否启动
ps aux | grep /lwh/data/postgresql | grep -v grep | wc -l #返回值不为0表示服务存在ps aux | grep /lwh/data/postgresql | grep -v grep | awk "{print $2}" #返回具体的pid表示服务存在或者:netstat -ntlp | grep 5432 #5432为pg默认端口
5)备份与还原
分为逻辑备份和物理备份。
1>pg_dump/pg_dumpall命令
pg_dumpall是将一个pg集群全部转存到另一个脚本文件(sql脚本、归档文件)中,而pg_dump命令可以选择一个数据库或部份表进行备份。pg_dump结合pg_restore使用,能灵活备份和恢复。
2>冷备份
最简单的物理备份就是冷备份,即:停止pg,然后拷贝pg的data目录。
3>热备份
即不停止数据库进行备份,常见的方法有:PITR方法、使用文件系统或块设备级别的快照功能完成备份。Linux下最简单的备份方式是使用LVM的快照功能。
6)时间相关命令
说明命令备注
查看数据库启动时间select pg_postmaster_start_time()
查看最后load配置文件的时间select pg_conf_load_time()pg_ctl reload后改变这个时间
显示当前数据库时区show timezone时区不一样的情况下,数据库时间和操作系统时间不一致。;PRC: People’s Republic of China
查看当前时间select now()
设置时区set time zone ‘GMT’PRC为北京时区
查看所有时区的名字SELECT * FROM pg_timezone_names
7)其它常用命令
说明命令备注
当前连接数据库select current_catalog, current_database();两者结果一样
查看pg是否正在做基础备份select pg_is_in_backup(),pg_backup_start_time();
查看数据库大小select pg_database_size("ngsoc"), pg_size_pretty(pg_database_size("ngsoc"));pg_size_pretty会转换成MB\GB等格式展示
3,数据类型
类型转换:
select "5"::int, "2014-09-09"::date;select int "5", date "2014-09-09";
常见操作符:
# + - * / %3 ^ 3 # 幂|/36.0 #平方根||/8.0 #立方根5! 或 !!5 #阶乘,结果都是120@-5.0 #绝对值# & (and) |(or) #(XOR) ~(not) << >>
1)布尔(boolean)
值:true\false\NULL 表示方法很多,如下:
create table lwh(id int, a boolean, b boolean);insert into lwh values (1,true,faLSE);insert into lwh values (2,"true","false");insert into lwh values (3,"t","f");insert into lwh values (4,"y","no");insert into lwh values (5,"1","0");select * from lwh;
常用操作符:is、and、or、not
2)数值
1>int
smallint(int2)、int(int4)、bigint(int8);
2>decimal(numeric,精确类型的小数)
decimal精度可达1000,适用于货币金额等要求精度的场合。 会影响运算速度。
3>float
real(非精确类型的浮点小数,float4)、double(非精确类型的浮点小数,float8);
浮点数(float)特殊值:Infinity(正无穷大)、-Infinity、NaN(不是一个数字),sql操作:
update table set x="Infinity" #不区分大小写
另外两个浮点数值做相等性比较时可能不符合预期。
4>money(8字节,货币类型)
完全保证精度,不同国家其输出格式不同。
show lc_monetary; #en_US.UTF-8输出就是$1.22select "1.22" :: money;set lc_monetary = "zh_CN.UTF-8"; #通过这个修改,可输出¥1.22
5>serial
serial(自动递增整数,serial4)、bigserial(大的自动递增整数,serial8)。 pg中的自增字段,通过序列(sequence)来实现的。
create table t (id serial);
等价于:
create sequence t_id_seq;create table t( id integer not null default nextval("t_id_seq"));alter sequence t_id_seq owned by t.id;
3)字符( varchar(n)、char(n)、text )
varchar(n)最大存储1GB,在mysql中最大是64kb; 长度为(2^n)-1。 (2^n)-1是好的磁盘或内存块对齐,对齐块更快。今天“块”的大小更大,内存和磁盘足够快,可以忽略对齐。char(n):定长不足补空白,最大存储1GB,存储空间为4+n。text:变长。 在大多数数据库中,定长char(n)有一定的性能优势;但在pg中,定长变长无区别。建议使用varchar(n)、text。
1>常见操作符和函数
描述示例结果备注
字符串连接`‘Post’‘greSQL’`
字符串拼接select CONCAT(‘Post’,‘gre’,‘SQL’)PostgreSQL
换为小写lower("TOm")tom做大小写无关的比较时使用
转换为大写upper("TOm")TOM
字符串截取substring(str, 1,2)第二个参数为起始位置,第三个参数为截取长度(可不填)
字符index获取position(",",str)
字符长度获取length(str)
字符串反转reverse(str)
4)二进制(bytea)
适用于存储图片等信息。
5)位串( bit(n)、bit varying(n) )
是一串由1和0组成的字符串。相比二进制类型,在位操作方面更方便。
bit(n),必须存储n位。bit varying(n),存储最长为n位。
6)日期和时间(date、time、timestamp)
time、timestamp根据是否包括时区又分为两种类型。interval 表示时间间隔。
pg中世纪可以精确到毫秒。
1>日期函数
--按照当前事务开始的时间返回数据。在整个事务中值不变。select current_time; --带时区。current_date,current_time, current_timestamp, current_time,current_timestamp(precision) select localtime; -- 10:13:42.334327,不带时区。localTimestamp, localTime(precision)...select now(); --2021-01-20 10:14:37.50845+08 包括时区,秒也保留到了6位小数 select now()::timestamp(0)without time zone; --2021-01-20 10:22:41select transaction_timestamp(); --当前事务开始的时间戳--返回实时时间,不受事务影响:statement_timestamp() --当前语句开始时的时间戳clock_timestamp() --实时时间戳,同一条sql中也可能不同timeofday() --类似clock_timestamp,但返回值为text字符串select age(timestamp "2011-05-02", timestamp "1980-05-01") ;--31 years 1 dayselect age(timestamp "2011-05-02") ;--9 years 8 mons 18 days, 相当于age(current_date, timestamp "2011-05-02")
函数函数说明举例备注
to_char日期转为格式化字符串to_char(time,"YYYY-MM-DD hh24:mi:ss") as time1
to_date
to_timestamp
2>日期运算
比较:date、timestamp、long可以通过>=、between and来比较计算
WHEREcreate_time BETWEEN (CURRENT_TIMESTAMP - INTERVAL "3 hour" --日期计算,可以是+或者-)AND CURRENT_TIMESTAMPselect date"2020-04-02" + integer"7"; --2020-04-09 dateselect date"2020-04-02" + interval"1 hour"; --2020-04-02 01:00:00 timestampselect date"2020-04-02" + time"3:00"; --2020-04-02 03:00:00 timestampselect time"3:00" + interval"1 hour"; --04:00:00 timeselect -interval"1 hour"; ---01:00:00 intervalselect date"2020-04-02" - date"2020-04-01"; --1--overlaps 两个时间戳重叠为trueselect (date "2020-04-02", date "2021-04-02") overlaps (date "2020-06-02", date "2022-04-02"); --true
3>日期特殊值
字符串使用类型描述
epochdate, timestamp1970-01-01 00:00:00+00(UNIX系统零时)
infinitytimestamp时间戳最大值,比任何时间都晚
-infinitytimestamp时间戳min
nowdate, time, timestamp当前事务开始时间
todaydate, timestamp今日午夜
tomorrowdate, timestamp明日午夜
yesterdaydate, timestamp昨日午夜
7)枚举
mysql也有枚举类型,用法稍微不同。
create type week as enum ("sun","mon","wed");create table lwh_duty(person text, weekday week);insert into lwh_duty values ("mary","sun");insert into lwh_duty values ("mary","Sun"); --报错,字符串不在枚举类型内。区分大小写。select * from lwh_duty where weekday = "Sun"; --报错--查看枚举类型的定义select * from pg_enum; --常见函数select enum_first("wed"::week);--sun,返回第一个枚举类型。wed可以是任意枚举值即可。同理还有enum_lastselect enum_range("wed"::week); --{sun,mon,wed},wed可以是任意枚举值即可。以有序数组的形式返回所有枚举类型--删除枚举 删除之前要清除所有依赖drop type enum_lwh_test;--枚举创建 表字段类型为枚举名即可create type enum_lwh_test as enum ("confirmed","unconfirmed");--枚举重命名 会一并修改相关依赖alter type enum_lwh_test rename to enum_lwh;--插入新值ALTER TYPE enum_lwh ADD VALUE "orange" AFTER "unconfirmed";
8)几何(pg特有类型)
包括类型:点(point)、直线(line)、线段(lseg)、路径(path)、多边形(polygon)、圆(cycle)。
9)网络地址(cidr、inet、macaddr,pg特有类型)
类型名称存储空间描述
cidr7或19字节ipv4或ipv6的网络地址 (总是显示掩码)
inet7或19字节ipv4或ipv6的网络地址或主机地址
macaddr6字节mac地址
--macaddr支持多种格式select "00e005664477"::macaddr;select "00E005:664477"::macaddr;--不区分大小写select "00-E0-05-66-44-77"::macaddr;select "00E005-664477"::macaddr;select "00E0.0566.4477"::macaddr;--运算select inet"192.0.0.1" < inet "192.0.0.2";-- true。大于等于、不等于<>select inet"192.0.0.3" << inet "192.0.0.0/24";-- true。包含于<<、包含>>select ~inet"0.0.0.255"; --255.255.255.0 位非select inet"0.0.0.255" & inet"0.0.0.255"; --0.0.0.255 位与&,位或|select inet"192.0.0.50" + 1; --192.0.0.51 + -select inet"192.0.0.50" - inet"192.0.0.0"; --50--其它函数……host(inet) --取主机地址hostmask(inet) --主机掩码地址netmask(inet) --子网掩码
10)数组(pg特有类型)
数组的类型可以是数据库内建的类型、用户自定义的类型、枚举或者组合类型。
1>定义
--数组可以定义长度、也可以不给。也可以定义多维数组。但定义长度和多维数组在实际使用中是无效的。如下面两种定义是等价的。create table lwh01(id int, col1 int[], col2 text[][]);create table lwh01(id int, col1 int[10], col2 text[]);
2>插入
--插入--数组通过单引号+大括号来表示,具体分隔符通过以下sql来查询,大部分情况下使用的是逗号分隔(box通过分号分隔,其它用逗号)。select typname, typdelim from pg_type where typname in ("int4","box");insert into lwh01 values(1, "{1,2,3}", "{1,2,3}");insert into lwh01 values(2, "{{1,2,3},{1,2,3}}", NULL);--通过ARRAY关键字使用数组构造器也可以输入数组insert into lwh01 values(3, ARRAY[1,2,3], ARRAY["1","2","3"]);--二维数组 array输入insert into lwh01 values(4, ARRAY[[1,2],[2,3]], NULL);--数组下标输入。默认从1开始,可以手动指定以0开始输入。insert into lwh01 values(5, "[0:2]={1,2,3}", NUll);
3>查询
--pg数组下标从1开始(也可以指定下标开始值)select id, col1, col1[0],col1[1],col1[2],col1[3],col1[4], col1[1][2], col1[1:2], col1[1][1:2] from lwh01;
4>常用操作符
操作操作符说明备注
等于= <>两个数组维度、元素个数及值和顺序完全一致为真
大于小于> <按BTree比较函数逐个元素比较
包含@>同理有<@,表示> ARRAY[1,2]结果t
重叠&&是否有共同元素。可跨纬度计算。ARRAY[1,2,3] && ARRAY[3,4]结果为t
连接``
在jpa中,两个数组取交集,即&&运算这样使用:
select ids && "{1}" :: int[] from book_info; --jpa中,sql的::
5>常用函数
功能| 操作 |备注 –|–|–|– 数组末尾追加 |array_append(ARRAY[2,3], 3); --{1,2,3}数组连接 | array_cat(ARRAY[2,3],ARRAY[2,3]); --{2,3,2,3}数组中移除特定值 | array_remove(ARRAY[2,3], 2); --{3}| 只支持一维数组 数组中替换某个值| array_replace(ARRAY[2,3],3,5);--{2,5}| 针对所有维度的数据 array2string | array_to_string(ARRAY[2,3],","); --2,3string2array| string_to_array("1,2,3", ","); --{1,2,3}
聚合函数array_agg:
select id, col3 from lwh01;--int, intidcol31122231425select id, array_agg(col3) from lwh01 group by id; --int arrayidarray_agg2{2,3,5}1{1,4}
11)复合类型(用户自定义类型)
类似于C的结构体,
12)xml类型
可以存储xml类型,自动校验是否合法。
13)json/jsonb
postgresql支持两种json数据类型:json和jsonb。与text不同,会自动校验格式是否合法。
1>概念
主要区别在于效率:json类型存储快,使用慢;jsonb类型存储稍慢,使用较快。 json是对输入的完整拷贝,使用时再去解析,所以它会保留输入的空格,重复键以及顺序等。 jsonb是解析输入后保存的二进制,它在解析时会删除不必要的空格和重复的键,顺序和输入可能也不相同。使用时不用再次解析。
json类型和pg类型映射:
json类型pg类型备注
stringtext
numbernumericjson中没有pg的“NAN”和“infinity”值
booleanbooleanjson仅支持小写的true false
null(none)sql中NULL表示的意思不同
2>常用函数和操作符
json和jsonb的操作与函数基本通用。
①数组操作
json和jsonb通用:
--如果用操作符->>,取出数据会自动转换为textselect "[{"a":"foo"},{"b":"bar"},{"c":"baz"}]"::json->2; --{"c":"baz"} 索引从0开始,从数组中取出index=2的对象select "["a", "b"]"::jsonb ?& array["a", "b"]; --true array中是否包含某些键(top-level keys,这些键是一个数组)select "["a", "b"]"::jsonb || "["c", "d"]"::jsonb; --["a", "b", "c", "d"] 两个数组求并集select "["a", "b"]"::jsonb || "["c", "d"]"::jsonb; --两个数组求并集select (ARRAY[11] || (select type from field where label = "名称") )select "["a", "b"]"::jsonb - 1; --["a"] 数组去除某个索引select "["a", {"b":1}]"::jsonb #- "{1,b}"; --["a", {}] 数组去除某个路径的键 --各种格式生成arrayselect json_build_array(1,2,"3",4,5); --[1, 2, "3", 4, 5] select array_to_json("{{1,5},{99,100}}"::int[]); --[[1,5],[99,100]] select json_array_length("[1,2,3,{"f1":1,"f2":[5,6]},4]"); --5 数组长度select * from json_array_elements("[1,true, [2,false]]");--取出数组中所有元素 json_array_elements_text返回text
②map操作
json和jsonb通用:
--如果用操作符->>,取出数据会自动转换为textselect "{"a": {"b":"foo"}}"::json->"a"; --{"b":"foo"} 从map中取出key为a的值--如果用操作符#>>,取出数据会自动转换为textselect "{"a": {"b":"foo"}}"::json #>"{a,b}"; --"foo" map输出特定路径对象select "{"a":1, "b":2}"::jsonb @> "{"b":2}"::jsonb; --true map中是否包含某个键值对 同理还有<@select "{"a":1, "b":2}"::jsonb ? "b"; --true map是否包含某个键(top-level keys)select "{"a":1, "b":2, "c":3}"::jsonb ?| array["b", "c"]; --true map中是否包含某些键(这些键是一个数组)select "{"a": "b"}"::jsonb - "a"; --{} map剔除某个键select "{"a": "b", "c": "d"}"::jsonb - "{a,c}"::text[]; --{} map剔除某些键--各种格式生成mapselect row_to_json(row(1,"foo","1")); --{"f1":1,"f2":"foo","f3":"1"}select json_build_object("foo",1,"bar",2); --{"foo" : 1, "bar" : 2} select json_object("{a, 1, b, "def", c, 3.5}"); --{"a" : "1", "b" : "def", "c" : "3.5"} select json_object("{{a, 1},{b, "def"},{c, 3.5}}");select json_object("{a, b}", "{1,2}"); --{"a" : "1", "b" : "2"}select * from json_each("{"a":"foo", "b":"bar"}"); --把jsonMap转换为键值对 json_each_text返回text--通过键路径获取值 json_extract_path_text返回textselect json_extract_path("{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}","f4"); --{"f5":99,"f6":"foo"} select json_extract_path("{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}","f4","f6");--"foo"
③常用函数
select to_json("Fred said "Hi.""::text); --"Fred said \"Hi.\"" string2json select json_typeof("-123.4"); --number --修改jsonb jsonb_setjsonb_set("[{"f1":1,"f2":null},2,null,3]", "{0,f1}","[2,3,4]", false)-- attributes为jsonb类型字段(对象转成的json)-- 第一个参数表示jsonb对象,第二个参数表示路径text[],第三个参数表示value(jsonb对象),第四个值表示无此值是否新建(默认为true)原值:{"a":"1"}update user_test set attributes = jsonb_set(attributes,"{a}",""0""::jsonb, false) where id = "8888";执行后:{"a":"0"}
3>索引
json类型没办法直接建索引,但是可以建函数索引。 jsonb类型的列上可以建索引,GIN索引可以高效的从jsonb内部的key/value对中搜索数据。(BTree索引效率较低)
GIN索引创建方式:
--使用默认的操作符jsonb_ops创建GIN索引:--每个key和value都作为一个单独的索引项--如:{“foo”:{“bar”:“baz”}},会创建3个索引项:“foo” “bar” “baz”create index idx_name on table_name using gin(index_col);--使用jsonb_path_ops操作符建GIN索引:(推荐)--为每个value创建一个索引项--如:{“foo”:{“bar”:“baz”}},会创建1个索引项:“foo” “bar” “baz”组合成一个Hash值作为索引项。因为索引相对较小,带来性能的提升。create index idx_name on table_name using gin(index_col jsonb_path_ops);
14)range(范围类型,pg特有类型)
主要用于范围快速搜索。 直接通过库里的开始值和结束值进行范围搜索效率较低,而使用range类型,通过创建空间索引的方式来执行范围搜索会大大提高效率。
15)对象标识符
16)伪类型
不能作为pg的字段,主要用于声明函数的参数和结果类型。
17)其他类型
类型描述备注
UUID128字节的数字。pg核心库没有提供生成UUID的函数
pg_lsnpg9.4以上版本支持。用于表示LSN的数据类型,64位大整数。LSN表示WAL日志的位置
4,SQL语法
1)库操作
创建、修改、删除、使用与常规sql语法一致。
查询当前数据库:
select current_database();
查询当前用户:
select user; 或者:select current_user;
2)模式
创建、修改、删除、使用与常规sql语法一致。 默认模式位public。
3)表操作
创建、修改、删除、使用与常规sql语法一致。。
pg表也支持TOAST(跨页存储的大字段,需要将行外数据存储到TOAST表)。
--获取数据库中所有表select * from pg_tables where schemaname="public";
1>更新插入一体
当主键或者unique key发生冲突时,什么都不做(同时也适用于多个字段的唯一性约束):
INSERT INTO test.upsert_test(id, "name")VALUES(1, "m"),(2, "n"),(4, "c")ON conflict(id) DO NOTHING;
upsert方法,冲突则更新,否则插入:
insert into "public"."user"(id, name)values(1,"a")ON conflict(id)DO UPDATE SET name = "b";
2>查询
表查询没有指定查询顺序时,按插入顺序进行排序。
--查询一个表是否存在select count(*) from pg_class where relname = "tablename";--查询所有的表SELECT * FROM pg_tables;--查询所有的视图SELECT * FROM pg_views;--查询表结构SELECT a.attnum,a.attname AS field,t.typname AS type,a.attlen AS length,a.atttypmod AS lengthvar,a.attnotnull AS notnull,b.description AS comment FROM pg_class c,pg_attribute a LEFT OUTER JOIN pg_description b ON a.attrelid=b.objoid AND a.attnum = b.objsubid,pg_type t WHERE c.relname = "person_wechat_label" and a.attnum > 0 and a.attrelid = c.oid and a.atttypid = t.oid ORDER BY a.attnum;--从数据库中导出数据到文件\copy (select * from "user") to "/tmp/1.txt";
a)similar to(pg特色)
类似like的用法,在like的基础上又增加了与POSIX正则表达式相同的模式匹配元字符。
select label FROM classify where label similar to "(36)+%" ;--检索以36开头或3636……开头的数据select label FROM classify where label like "(36)+%" ; --检索(36)+开头的数据
元字符功能
()表示独立逻辑项目
``
*重复前面的项0次或更多次
+重复前面的项一次或更多次
?重复前面的项0次或1次
{m}重复前面的项m次
{m, }重复前面的项m次或更多次
{m,n}重复前面的项至少m次,不超过n次
[…]
b)POSIX 正则表达式
pg中有两种正则表达式:
区别SQL正则表达式POSIX 正则表达式
概念遵循sql语句中like、similar to语法脚本语言中的标准正则表达式
任意一个字符_.
任意个字符%.*
POSIX 正则表达式:
模式匹配操作符功能
~匹配正则表达式,区分大小写
~*匹配正则表达式,不区分大小写
!~不匹配正则表达式,区分大小写
!~*-
--下面两种语句功能一致:select "osdba" ~"a"; --t select "osdba" similar to "%a%"; --tselect "osdba" ~"b|a";--t
c) substring函数(pg特色) 这个函数功能强大,可以使用正则表达式。
3>表继承
表继承是pg特有的。
create table persons_lwh( name text, age int, sex boolean);create table students_lwh( class_no int)INHERITS(persons_lwh); --继承。--父表的检查约束、非空约束会被子表继承,但唯一、主键、外键约束子表不会继承。--一个子表可以继承多个父表,多个相同字段必须类型一致,融合后在子表中只有一个字段。insert into students_lwh values("Mary",15,true,1); --向子表插入数据,父子表都有数据insert into persons_lwh values("Bob",15,true);--向父表插入数据,只有父表有数据select * from persons_lwh;select * from students_lwh;select * from only persons_lwh; --添加only,只获取直接插入父表的数据
4>表空间
pg中的表空间就是为表一指定个存储目录,主要用于把表存放到不同的存储目录。
4)表分区
1>概念
表分区是逻辑上把大表分割成物理上几块,如按时区分、按类型分等。
优点
删除更快。如按时间分区,删除历史数据直接删除对应分区表。查询更快。如按时间分区,较早时间的表几乎很少查询,各个分区表有各自的索引,使用频率高的分区表的索引就可以完全缓存到内存中。修改更快。访问具体分区表,而不是全表扫描。节省资源。根据访问频率把不常访问的数据存储到不同的物理介质上。
2>表继承分区
注意:通过触发器创建表,主表的唯一索引可以创建但是不起作用!!!
--表继承create table sales_detail(...sale_date...);--父表,不存数据create table sales_detail_y2014m01 ( check (sale_date >= DATE"2014-01-01" and sale < DATE"2014-02-01") --check约束)INHERITS(sales_detail); --子表继承父表--在各个分区表的分区键上建立索引create index sales_detail_y2014m01_sale_date on sales_detail_y2014m01 (sale_date);--建立规则或触发器,把对主表的数据插入重定向到具体分表。create RULE sales_detail_insert_y2014m01 AS ON insert to sales_detail where (sale_date >= DATE"2014-01-01" and sale < DATE"2014-02-01")DO INSTEAD insett into sales_detail_y2014m01 values(NEW.*);
分表通过规则或触发器优缺点对比:
相比触发器,规则开销很大。批量插入的情况下,规则效率更高。copy插入数据不会触发规则,但会触发触发器。分表之外的数据,再次插入父表时,触发器会报错,但规则会把这些规则之外的数据插入主表。
3>声明式分区
pg内部通过表继承来实现分区表。pg10.x通过声明式分区直接创建分区表,但其内部原理依然是表继承。
相比表继承分区,不需要在父表创建各种触发器(降低维护成本),对父表的DML操作会自动路由到相应分区。
目前仅支持范围分区和列表分区。
--范围分区 --创建主表1. 创建全局主键必须携带分区字段2. 不允许全局创建索引,可以在分表上创建索引。3. 删除主表不会删除子表,通过级联删除可以一起删除。4. 查询主表时若在where条件中携带分区字段(如日期),可直接去分区表检索,提高检索速度。注意:这个字段不包含运算,否则失效。create table sales_detail( ... sale_date date not null, ...) PARTITION BY RANGE(sale_date); --通过PARTITION BY来支持分区。不能给没有分区表的分区插入数据。--创建分区表(分区表需要手动进行创建,可以用定时任务一次创建多个)create table sales_detail_y2014m01 PARTITION OF sales_detail --通过PARTITION OF指定分区表分区。FOR VALUES FROM ("2014-01-01") TO ("2014-02-01"); --查看所有的分区表select relname from pg_catalog.pg_class where relispartition = "t";
--列表分区create table test_list_part(id int, state boolean) PARTITION BY list(state);create table test_list_part_t partition of test_list_part for values in ("t");create table test_list_part_f partition of test_list_part for values in ("f"); insert into test_list_part values ("1","t");insert into test_list_part values ("1","f"); create index on test_list_part_f (state);create index on test_list_part_t (state);
④优化
1.打开约束排除(postgresql.conf中的constraint_exclusion设置为on)。 sql查询中,where语句的过滤条件与分区表的check条件进行对比,直接跳过不需要扫描的分区表。 注意:分区字段的where语句如果包含计算,可能会扫描全表,需要解释执行确认。
select count(*) from sales_detail where sale_date >= DATE"2014-12-01";--同各个分区表上的check条件进行对比,可知只需要扫描主表和分表sales_detail_y2014m12。
⑤主键
可能我的navicat版本太低了看不见主键,通过以下sql可以查询到主键。
SELECTpg_attribute.attname AS colname,pg_type.typname AS typename,pg_constraint.conname AS pk_name FROMpg_constraintINNER JOIN pg_class ON pg_constraint.conrelid = pg_class.oidINNER JOIN pg_attribute ON pg_attribute.attrelid = pg_class.oid AND pg_attribute.attnum = pg_constraint.conkey [ 2 ]INNER JOIN pg_type ON pg_type.oid = pg_attribute.atttypid WHEREpg_class.relname = "tbl_alarm_judge_conclusion" AND pg_constraint.contype = "p";--pg_constraint.contype : c = 检查约束, f = 外键约束, p = 主键约束, u = 唯一约束 t = 约束触发器 x = 排斥约束
5)序列
序列对象(也叫序列生成器)就是用CREATE SEQUENCE 创建的特殊的单行表。一个序列对象通常用于为行或者表生成唯一的标识符。通常用于表的主键自增。
mysql中的序列有以下两个限制,但pg中的序列没有。
自增长只能用于表中的一个字段;自增长只能被分配给固定表的固定的某一个字段,不能被多个表使用。
①创建
1> serial
将id类型设置为:serial,pg会自动创建一个序列,同时将列设置为INT,默认值设置为nextval(‘序列’)。serial8会将列设置为int8(long)
2> sequence(序列)
--[TEMPORARY | TEMP] 临时序列,在会话结束时自动删除;除非用模式修饰,否则同一个会话中同名的非临时序列是不可见的。create [TEMPORARY | TEMP] sequence seq_name; --nextval("seq_name") 表示递增序列seq_name并返回新值。字符串会自动转换为regclass类型--setval("seq_name", bigint) 设置序列当前数值create table test (id int default nextval("seq_name"), info text);
CREATE SEQUENCEIF NOT EXISTS PUBLIC .role_id_seq --序列名 START WITH 1 --指定序列的起点,缺省初始值对于递增序列为minvalue, 对于递减序列为maxvalue。 INCREMENT BY 1 --递增量,缺省为1;递减为负数 NO MINVALUE --指定序列的最小值, 如:minvalue 1 NO MAXVALUE --指定序列的最大值,递减序列最大值为-1 CACHE 1 --为快速访问而在内存里预先存储多少个序列号,缺省值为1,表示一次只能生成一个值,也就是说没有缓存。 OWNED BY {table.column | NONE} --将序列关联到一个特定的表字段上,在删除该字段或其所在的表时将自动删除绑定的序列;NONE表示无关联。 CYCLE --默认不添加cycle选项,创建出来的序列满时会报错;添加cycle时,序列会从开始值重新开始。 ;
② 给已有的字段创建添加自增,并且自增值从最大的id+1开始
--将下一次的自增值设置成最大id+1select setval("user_info_id_seq",(select max(id)+1 from user_info));
③修改序列
alter sequence serialincrement by 3restart with 10; --是一个可选选项,它改变序列的当前值 select nextval("serial");
④删除序列
DROP SEQUENCE [ IF EXISTS ] name [, ...] [ CASCADE | RESTRICT ]--IF EXISTS 如果指定的序列不存在,那么发出一个 notice 而不是抛出一个错误。--CASCADE 级联删除依赖序列的对象。--RESTRICT 如果存在任何依赖的对象,则拒绝删除序列。这个是缺省。drop sequence serial;
⑤序列和事务
事务回滚不会影响序列。
begin;select netval("seqtest01"); --3rollback;select currval("seqtest01"); --3
⑥cache
如果cache大于1,当序列被用于多会话时,每个会话在每次访问序列对象的过程中都会分配并缓存随后的序列值,会话结束时丢失没有使用的数字,从而导致序列出现空洞。 多个会话的情况下,如果cache大于1,那么只能保证nextval值是唯一的,缺不按顺序生成。比如cache=10,会话A保留了1……10并且返回nextval=1,会话B保留了11……20。会话A返回nextval=1之前会话B可能先返回nextval=11。
6)触发器(Trigger)
触发器是一种由事件自动触发执行的特殊的存储过程。主要用于加强数据的完整性约束和业务规则上的约束。 PostgreSQL的触发器是数据库自动执行\指定的数据库事件发生时调用的回调函数。 注意:
如果有多个相同类型的触发器定义了相同的事件,他们将被触发名称是按字母顺序排列。
1>创建触发器
语句触发:(修改0行的操作依然会触发。按语句触发,而不管这条语句操作了多少行)
CREATE TRIGGER stu_trigger AFTER INSERT OR DELETE OR UPDATE ON stu_info --AFTER 可以换成BEFORE,在语句执行前触发。行级别的AFTER触发器在任何语句级别的AFTER触发器之前触发。FOR STATEMENT EXECUTE PROCEDURE stu_trigger_function ();
针对字段触发:
CREATE TRIGGER stu_trigger AFTER INSERT OR UPDATE OF birthday OR DELETE ON stu_info FOR EACH ROW EXECUTE PROCEDURE stu_trigger_function (); --stu_trigger_function 为触发函数
行触发:(如果执行的语句没有更新实际的行,那么不会+触发)
CREATE TRIGGER example_trigger AFTER INSERT OR DELETE OR UPDATE ON COMPANY FOR EACH ROW EXECUTE PROCEDURE auditlogfunc();
2>删除
触发器删除不会删除对应的触发函数;但删除表时,表上的触发器会一并删除。
DROP TRIGGER if exists stu_trigger ON stu_info [CASCADE | RESTRRICT]; --中括号中的可省略。CASCADE 级联删除依赖此触发器的对象;RESTRRICT是默认值,有依赖对象存在就拒绝删除。
3>触发函数
触发函数有返回值。 对于BEFORE和INSTEAD OF这类行级触发器来说:
返回NULL,表示忽略当前行的操作。也不会触发其它触发器。返回非NULL:对于INSERT和UPDATE操作来说,返回的行将成为被插入的行或者将要更新的行。每个触发器返回的行将成为下一个触发器的输入。 对于AFTER这类行级触发器:返回值会被忽略。
触发函数常用特殊变量:
NEW: 1. INSERT/UPDATE 行级触发器中新的数据行,数据类型是RECORD;2. 语句级别触发器、DELETE操作触发器 中此变量未分配。OLD:3. UPDATE/DELETE 行级触发器中原有的数据行,数据类型是RECORD;4. 语句级别触发器、INSERT操作触发器 中此变量未分配。TG_NAME: 触发器名。数据类型:name。TG_WHEN: 是 BEFORE/AFTER 触发器。TG_LEVEL:是 ROW/STATEMENT 触发器。TG_OP:是 INSERT/UPDATE/DELETE/TRUNCATE 之一的字符串,表示DML语句类型。TG_TABLE_NAME:触发器所在表的名称。同理有TG_TABLE_SCHEMA(模式)。
CREATEOR REPLACE FUNCTION stu_trigger_function () RETURNS TRIGGER AS$BODY$DECLARE_birthday TIMESTAMP;_id int;BEGIN IF TG_OP = "INSERT" THEN SELECT birthday INTO _birthday FROM stu_info WHERE name= NEW .name AND class_id= NEW .class_id; IF _birthday is NULL THEN INSERT INTO stu_info ( ID, name, birthday , class_id) VALUES ( NEW . ID, NEW .name, NEW .first_occur_time, NEW .class_id) ; ELSE IF NEW .birthday < _birthday THEN UPDATE stu_info SET ID = NEW . ID, birthday = NEW .birthday ; END IF ; END IF ; ELSE IF TG_OP = "DELETE" THEN DELETE FROM stu_info A WHERE A . ID = OLD . ID ; RETURN OLD ; ELSE IF TG_OP = "UPDATE" THEN if UPDATE(birthday ) THEN SELECT ID,birthday INTO _id, _birthday FROM stu_info WHERE class_id= OLD .class_id AND name= OLD .name; IF ( _id != 0 AND _birthday > OLD .birthday ) THEN UPDATE stu_info SET ID = _id, birthday = _birthday ; END IF ; END IF; END IF ; END IF ; END IF ; RETURN NEW; --语句级触发函数可以显示的写:RETURN NULLEND ;$BODY$LANGUAGE plpgsql;--删除触发函数drop FUNCTION add_stu_trigger();
4>事件触发器
pg9.3开始支持Event Trigger,主要用于弥补pg以前版本不支持DDL触发器的不足。
7)函数
1>创建
CREATE [OR REPLACE] FUNCTION function_name (arguments) RETURNS return_datatype AS $variable_name$ DECLARE declaration; [...] BEGIN < function_body > [...] RETURN { variable_name | value } END; LANGUAGE plpgsql;
function_name:指定函数的名称。 arguments: 函数参数 [OR REPLACE]:是可选的,它允许修改/替换现有函数。 DECLARE:定义参数(参数名写在前面 类型写在后面)。 BEGIN~END: 在中间写方法主体。 RETURN:指定要从函数返回的数据类型(它可以是基础,复合或域类型,或者也可以引用表列的类型)。 LANGUAGE:它指定实现该函数的语言的名称。 可以是SQL,PL/pgSQL,C, Python等。
2>函数的参数说明
参数说明
IN可以将 IN 参数传递给函数,但无法从返回结果里再获取到。
OUTOUT 参数经常用于一个函数需要返回多个值,所以不需要 RETURN 语句。
INOUTINOUT 参数是 IN 和 OUT 参数的组合。这意味着调用者可以将值传递给函数,函数然后改变参数并且将该值作为结果的一部分传递回去。
VARIADICPostgreSQL 函数可以接受可变数量的参数,其中一个条件是所有参数具有相同的数据类型。参数作为数组传递给函数。
参数使用例子:
CREATE OR REPLACE FUNCTION hi_lo( IN a NUMERIC, IN b NUMERIC, OUT c NUMERIC, OUT hi NUMERIC, INOUT lo NUMERIC)AS $$BEGIN c:= GREATEST(a,b); hi:= LEAST(a,b); lo:=GREATEST(a,b);END; $$ LANGUAGE plpgsql;
3>函数重载
与 Java 等编程语言相同,PostgreSQL 允许多个函数具有相同的名称,只要参数不同即可。如果多个函数具有相同的名称,那么我们说这些函数是重载的。当一个函数被调用时,PostgreSQL 根据输入参数调用确切的函数。
4>块结构
一个 PostgreSQL 函数由块(block)进行组织。
[ DECLARE 声明 ] --可以没有BEGIN 主体; --必需 ...END;--声明部分中的每个语句都以分号(;)结尾。 主体部分中的每个语句也以分号(;)结尾。
8)视图
--获取数据库中所有viewselect * from pg_views where schemaname="public";
9)索引
10)用户及权限管理
pg中角色和用户没区别。超级用户为postgres。
11)事务、并发和锁
保存点(savePoint):在一个大的事务中,可以把操作过程分成几个部分,第一个部分执行成功后可以建一个保存点,若后面的部分执行失败,则回滚到此保存点,而不必回滚整个事务。咨询锁(Advisory Lock):session级别和事务级别。pg数据库提供一种与具体表数据无关的锁,pg将变成一个锁服务提供中心。主要场景:多个进程访问同一个数据库、分布式系统中类似Zookeeper的锁服务。
12)规则(Rule)
规则系统更准确地说是查询重写规则系统,使用时也可以被函数和触发器替代,但原理和使用场景不同(这在上文讲分表的时候就提到过)。对于批量操作,规则比触发器效率更高。
1>SELECT规则
create RULE "_RETURN" as on select to myview Do instead select * from mytable;#相当于create table myview (same column list as mytab);
2>更新规则
create [or replace] RULE name as on event #event 值为SELECT/INSERT/UPDATE/DELETEto tableName [where condition] do [also | instead] {nothing | command} # also表示执行原操作后还执行一些附加操作 如:also insert into mytab_log...; instead表示把原操作替换为后面的command操作
3>权限
规则从属于表和视图
5,执行计划
explain sql语句; #查看执行计划。也可以使用navicat的解释功能查看。
1)多表连接查询
①Nest Loop Join(嵌套循环连接)
1>场景
适合两个表的数据量都比较少的情况(最简单的 table join 方式)。
外表为小表,且过滤后的数据量较少。内表的关联列上有高效索引(主键或者唯一性索引)。
2>举例
# 内表(t4)被外表(t5)驱动。外表返回的每一行都要在内表中检索找到与它匹配的行,因此整个查询返回的结果集不能太大(大于1 万不适合)select t4.*,t5.* from tmp_t4 t4, tmp_t5 t5 where 1=1 and t4.id = t5.id and t4.id = 1;
相当于for循环:
for(t4.data in tmp_t4) { t5.data in tmp_t5 on t5.data = t4.data }
②Hash JOIN(哈希、散列连接)
1>场景
针对那些没有索引或者其中任一个有索引的大表。 哈希连接只能应用于等值连接(如WHERE A.COL3 = B.COL4)、非等值连接(WHERE A.COL3 > B.COL4)、外连接(WHERE A.COL3 = B.COL4(+))。
2>操作步骤
优化器使用两个表中较小的表(或数据源)利用连接键在内存中建立散列表,然后扫描较大的表并探测散列表,找出与散列表匹配的行。 这种方式适用于较小的表完全可以放于内存中的情况,这样总成本就是访问两个表的成本之和。但是在表很大的情况下并不能完全放入内存,这时优化器会将它分割成若干不同的分区,不能放入内存的部分就把该分区写入磁盘的临时段,此时要有较大的临时段从而尽量提高I/O 的性能。
③Sort Merge JOIN
1>场景
通常Hash JOIN的性能都优于Merge JOIN,对于那些连接列上有索引的表(已排好序)Merge JOIN性能会优于Hash JOIN。
2>操作步骤
mrege join的性能开销几乎都在前两步。
对连接的每个表做全表扫描(table access full);对table access full的结果进行排序。进行merge join对排序结果进行合并。
在全表扫描比索引范围扫描再通过rowid进行表访问更可取的情况下,merge join会比nested loops性能更佳。当表特别小或特别巨大的时候,实行全表访问可能会比索引范围扫描更有效。
6,数据库优化
1)SQL优化
对于重复的代码逻辑,sql执行速度远远大于代码逻辑。 但是,由于sql难以测试、难以复用、难以加工变量,对于复杂的逻辑不建议用在sql中。代码可以分成模块、逻辑独立、方便测试。
sql优化的思路有两种:一是:
即去掉无用的步骤;二是优化算法,如让sql走更优的执行计划上。
①基于规则优化(RBO)和基于代价优化(CBO)
RBO和CBO是两种数据库引擎在执行sql语句时的优化策略。
总结: 基于规则的优化器更像是一个经验丰富熟知各条路段的老司机,大部分情况可以根据自己的经验来判断走哪条路可以更快的到达目的地,而基于代价的优化更像手机里面的地图,它可以选择出许多不同的路径根据实时的路况信息综合考虑路程长度,交通状况来挑出最优的路径。
2)配置优化
pg中与内存有关的配置参数:
1>shared_buffers(共享缓存区)
i>工作原理
shared_buffers是一个8KB的数组,postgres在从磁盘中查询数据前,会先查找shared_buffers的页,如果命中,就直接返回,避免从磁盘查询。 多个进程通过共享内存技术来共享缓存中的数据。
shared_buffers存储什么? 表数据; 索引,索引也存储在8K块中; 执行计划,存储基于会话的执行计划,会话结束,缓存的计划也就被丢弃。
什么时候加载shared_buffers? 1)在访问数据时,数据会先加载到os缓存,然后再加载到shared_buffers,这个加载过程可能是一些查询,也可以使用pg_prewarm预热缓存。 2)当然也可能同时存在os和shared_buffers两份一样的缓存(双缓存)。 3)查找到的时候会先在shared_buffers查找是否有缓存,如果没有再到os缓存查找,最后再从磁盘获取。 4)os缓存使用简单的LRU(移除最近最久未使用的缓存),而数据库采用的优化的时钟扫描,即缓存使用频率高的会被保存,低的被移除。
ii>优化策略
提高shared_buffers,增加缓存命中率,提高查询效率。 同时为了避免Double Buffering问题,将shared_buffers设置较小,更多的内存留给文件系统使用。
【Double Buffering(双缓存)】问题: pg的数据文件都存储在文件系统中,os的文件系统也有缓存,这导致pg的数据库副本可能同时存在于共享内存和文件系统中,造成内存利用率低的问题。 Oracle中通过设置Birect I/O避免双缓存问题,但pg不支持。 shared_buffers的大小不应该超过内存的1/4。
shared_buffers设置的合理范围 1)windows服务器有用范围是64MB到512MB,默认128MB 2)linux服务器建议设置为25%,亚马逊服务器设置为75%(避免双缓存,数据会存储在os和shared_buffers两份) os缓存的重要性:数据写入时,从内存到磁盘,这个页面就会被标记为脏页,一旦被标记为脏页,它就会被刷新到os缓存,然后写入磁盘。所以如果os高速缓存大小较小,则它不能重新排序写入并优化io,这对于繁重的写入来说非常致命,因此os的缓存大小也非常重要。给予shared_buffers太大或太小都会损害性能。
shared_buffers调整策略
2> work_mem
为每个进程单独分配的内存,主要用于group by, sort, hash agg, hash join 等操作。 注意:work_mem是每次分配的内存,加入有M个并发进程,每个进程有N个HASH操作,那么需要分配的内存为 MNwork_mem。因此work_mem不宜设置太大,通常保持默认的4MB即可,如果设置的太大超过256MB,很容易因为瞬间的大并发操作导致oom。
3>maintenance_work_mem
为每个进程单独分配的内存,主要进行维护操作时需要的内存,如VACUUM、create index、ALTER TABLE ADD FOREIGN KEY等操作需要的内存。
4>autovacuum_work_mem
pg9.4版本新增参数。 9.4之后,AutoVacuum的worker进程分配的内存由参数autovacuum_work_mem控制,手动Vacuum时分配的内存由maintenance_work_mem 控制。9.4之前都用maintenance_work_mem 参数。 默认值为-1,表示与maintenance_work_mem 一样。 vacuum 大小 = autovacuum_max_workers * autovacuum_work_mem
5>temp_buffers(临时表缓存)
为每个不同的进程单独分配的内存,不在共享内存中,默认为8MB。
6>wal_buffers(WAL日志缓存大小)
默认为-1,表示根据shared_buffer的大小自动设置。
7>huge_pages(是否使用大页)
默认值为try,表示尽量使用大页。若os未开启大页,不使用大页内存,不影响数据库正常使用。
8>effective_cache_size(sql执行中的实际磁盘缓存)
与具体内存分配无关
3)sql审计
相关配置:
参数调整说明
log_min_duration_statementsql审计记录的标准,超过该时长的sql将被记录到日志文件。默认为-1,不记录超时sql。
log_statementnone默认,不记录;all-记录所有语句;ddl-记录所有数据定义语句;mod记录所有ddl和数据修改语句;
log_min_error_statement控制日志中是否记录导致数据库出现错误的SQL语句。默认为error
4)排查sql
-- 查看表结构 SELECT column_name,data_type FROM information_schema.columns WHERE table_name = "表名"; -- 展示在数据库中当前正在执行多少查询 SELECT datname, count(*) AS open, count(*) FILTER (WHERE state = "active") AS active, count(*) FILTER (WHERE state = "idle") AS idle, count(*) FILTER (WHERE state = "idle in transaction") AS idle_in_trans FROM pg_stat_activity GROUP BY ROLLUP(1) -- 查看事务已经打开了多久SELECT pid, xact_start, now() - xact_start AS duration FROM pg_stat_activity WHERE state LIKE "%transaction%" ORDER BY 3 DESC; -- 检查是否有长查询运行 SELECT now() - query_start AS duration, datname, query FROM pg_stat_activity WHERE state = "active" ORDER BY 1 DESC; -- 查看慢查询日志是否开启 SHOW log_min_duration_statement; -- 设置慢查询日志 ALTER DATABASE test SET log_min_duration_statement TO 10000; -- 查找经常被扫描的大型表 SELECT schemaname, relname, seq_scan, seq_tup_read, idx_scan, seq_tup_read / seq_scan AS avg FROM pg_stat_user_tables WHERE seq_scan > 0 ORDER BY seq_tup_read DESC LIMIT 20; -- 跟踪 vacuum 进度 SELECT * FROM pg_stat_progress_vacuum ;
7,内部机制与原理
1)进程架构模型
启动pg,主进程为Postmaster(pg的bin目录下,是一个指向Postgres的链接)。Postmaster是整个数据库实例的总控进程,负责启动和关闭数据库实例,同时fork出一些与数据库实例相关的辅助进程,并对其进行管理。
辅助进程作用配置
Logger系统日志参数logging_collect设置为on时启动该辅助进程
每次客户端与数据库建立连接时,pg数据库都会启动一个服务进程来为该连接服务,故而是进程架构模型,而MySQL是线程架构模型。当某个服务进程报错时,Postmaster主进程会自动完成系统恢复,恢复过程中停掉所有的服务进程,然后进行数据的一致性恢复,恢复完成后数据库才能接受新的连接。
--查询服务进程PID: 通过count(*)获取当前连接数select pid,usename,client_addr,client_port from pg_stat_activity;
2)autovacuum进程
autovacuum 是 postgresql 里非常重要的一个服务端进程,能够自动运行,在一定条件下自动触发对 dead tuples 进行清理并对表进行分析。 在pg中更新、删除行后,数据行并不会马上从数据块中清理掉,而是需要等VACUUM时时清理。为了加快VACUUM速度并降低对系统I/O性能的影响,pg8.4.1之后为每个数据块文件加了一个后缀为“_vm”的文件(可见性映射表文件,VM文件)。这个文件为每个数据块存储了一个标志位,标记数据块中是否存在要清理的tuple。
VACUUM有两种方式:
Lazy VACUUM :使用VM文件,扫描部分数据块。Full VACUUM :全量扫描数据块。
vacuum相关的配置:
参数名说明优化思路
autovacuum默认为on,表示是否开起autovacuum。当需要冻结xid时,尽管此值为off,PG也会进行vacuum。
autovacuum_naptime下一次vacuum的时间,默认1min通过缩短实际,调整回收频率,减少每次回收量,可以减小wal压力
log_autovacuum_min_duration向日志打印autovacuum的统计信息(以及资源消耗),大于阈值,输出这次autovacuum触发的事件的统计信息 。 “-1”表示不记录。“0”表示每次都记录。
autovacuum_max_workers最大同时运行的worker数量,不包含launcher本身。CPU核多、IO优秀时,当DELETE\UPDATE非常频繁时适量调多点。注意最多可能消耗这么多内存: # autovacuum_max_workers * autovacuum mem(autovacuum_work_mem)
autovacuum_vacuum_threshold默认50。与autovacuum_vacuum_scale_factor(默认值为20%)配合使用。当update,delete的tuples数量超过autovacuum_vacuum_scale_factor*table_size+autovacuum_vacuum_threshold时,进行vacuum。改小可以降低vacuum触发条件,提高vacuum频率
autovacuum_analyze_threshold默认50。与autovacuum_analyze_scale_factor(默认10%)配合使用。当update,insert,delete的tuples数量超过autovacuum_analyze_scale_factor*table_size+autovacuum_analyze_threshold时,进行analyze。改小可以降低vacuum触发条件,提高vacuum频率
autovacuum_freeze_max_age和autovacuum_multixact_freeze_max_age前者200 million,后者400 million。离下一次进行xid冻结的最大事务数。 如果表的事务ID年龄大于该值, 即使未开启autovacuum也会强制触发FREEZE,并告警Preventing Transaction ID Wraparound Failures。设置较大值,减少因事务id消耗造成全表扫描的频率。(1000million、1200million)
autovacuum_vacuum_cost_delay如果为-1,取vacuum_cost_delay值。autovacuum触发的vacuum、freeze、analyze的平滑化调度。设置过大,会导致AUTOVACUUM launcher触发的vacuum耗时过长。特别是大表,耗时会非常长,可能导致膨胀等问题。可以调小一点,0.
autovacuum_vacuum_cost_limit如果为-1,到vacuum_cost_limit的值,这个值是所有worker的累加值。
vacuum_freeze_table_age当表的年龄大于vacuum_freeze_table_age,则自动转换成vacuum freeze调高可以降低vacuum freeze的频率
vacuum_multixact_freeze_table_age当表的年龄大于autovacuum_freeze_max_age,也会强制触发vacuum freeze调高可以降低vacuum freeze的频率
如果开启了autovacuum,当垃圾记录数大于 autovacuum_vacuum_threshold + autovacuum_vacuum_scale_factor*reltuples ,autovacuum launcher触发普通的vacuum。 当表的年龄大于vacuum_freeze_table_age,则自动转换成vacuum freeze。如果开启了autovacuum,当新增记录数大于autovacuum_analyze_threshold + autovacuum_analyze_scale_factor*reltuples,autovacuum launcher触发analyze。即使没有开启autovacuum,当表的年龄大于autovacuum_freeze_max_age,也会强制触发vacuum freeze。
3)pg物理存储结构
①数据块结构
数据块大小默认8KB,最大为32KB,一个数据块中存储了多行数据。
块头 包括: a. 块的checksum值; b. 空闲空间的起始位置和结束位置; c. 特殊数据的起始位置; d. 其它信息。行指针:向后顺序排列。是一个32bit的数字,具体结构: a. 行内容偏移量,15bit;能表示的最大偏移量是215,因此pg中块最大为32kb b. 指针的标记,2bit; c. 行内容的长度,15bit。行内容:从块尾向前反向排列。空闲空间:行数据指针和行数据内容之间的空间。
②Tuple结构(数据行)
8,多版本并发控制(Multi-Version Concurrency Control,MVCC)
MVCC是数据库中并发访问数据时保证数据一致性的一种方法。实现MVCC的方法有以下两种:
写新数据时,把原数据移到一个单独的位置,如回滚段中,其它用户读数据时,从回滚段中把原数据读出来。(Oracle和Mysql数据库中的InnoDB引擎使用这种方法)写新数据时,原数据不删除,而是把新数据插入进来。(pg使用这种方法)
1)pg MVCC的优缺点
pg在事务提交前,只需要访问原来的数据;提交后,系统更新元组的存储标识,直到Vaccum进程回收为止。
相比InnoDB和Oracle,pg多版本优势在于: ① 事务回滚可以立即完成; ② 数据可以进行很多更新,不必像Oracle和InnoDB那样需要经常保证回滚段不会被用完,也不会像Oracle数据库那样,经常遇到ORA-1555错误的困扰。
劣势在于: ① 旧数据需要Vaccum清理。 ② 旧版本数据的存在降低查询速率,需要扫描更多的数据块。
2)事务ID及回卷
1>xmin 表系统字段
插入该行版本的事务ID。
2> xman 表系统字段
删除此行时的事务ID。 第一次插入时,xman=0。如果xman>0,说明删除事务未提交或者被回滚了。
当两个事务同时访问记录时,通过xmin和xman的标记判断记录的版本,根据版本号与自己当前事务标识比较,确定数据权限。
3> cmin 表系统字段
事务内部的插入类操作的命令ID,此标识是从0开始。
4> xman 表系统字段
事务内部的删除类操作的命令ID。如果不是删除命令, xman = 0。
5>事务ID:xid
32bit的数字,从3开始,连续递增。0 1 2是系统预留ID,这三个ID比任何普通xid都要旧: InvalidTransactionId=0:表示是无效的事务ID;表示还未分配事务ID。 BootstrapTransactionId=1:表示系统表初始化时的事务ID;表示Initdb服务正在初始化系统表。 FrozenTransactionId=2:冻结的事务ID。
6>回卷
xid一直递增达到2^32为最大值,然后继续从头开始,以前的xid比新的xid大,导致比较新旧事务空难,即事务回卷问题。 为了确保事务的可见性需要频繁判断事务之间的新旧关系,如:数据行中已提交的事务比当前事务更早,则这条数据行对当前事务可见。
事务ID的比较新旧的公式如下:diff = (int32) (id1 - id2); 是一个有符号的int32。
事务ID的比较代码:
/* * TransactionIdPrecedes --- is id1 logically < id2? */ bool TransactionIdPrecedes(TransactionId id1, TransactionId id2) // 结果返回一个bool值 {/* * If either ID is a permanent XID then we can just do unsigned * comparison. If both are normal, do a modulo-2^32 comparison. */ int32diff; if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2)) //若其中一个是特殊id即id为0 1 2,则另一个id一定较新(较大) /*验证: *1)id1=10, id2=2 那么return false,说明id1更新。即普通事务更新 *2)id1=2, id2=10 那么return true,说明id2更新。即普通事务更新 */ return (id1 < id2); //两个普通id的比较,转换为int32带符号,第一位为符号位。/*验证: * id1=2^31+101, id2=100, id1 - id2= 2^31+1 diff=-1 (大于2^31为负数),return true,id2更新。(事务回卷)* 那么如果id2确实是很早很早之前的旧事务怎么办呢?根据pg规定的freeze原则,如果id2是很早很早的事务,两事务年龄差又大于2^31,那么id2进行事务冻结。按之前的if逻辑,id1更新。*/ diff = (int32) (id1 - id2); return (diff < 0); }
7>事务冻结(freeze)
pg规定,最早和最新两个事务之间年龄差对多为231。 当超过231时,就把旧的事务换成一个FrozenTransactionId=2的特殊事务,当正常事务ID与冻结事务ID比较时,会认为正常xid比FrozenTransactionId更新。即:xid空间虽然有232,但被一分为二,对某个特定的xid,其后231个xid属于未来,均不可见;其前231个xid属于过去,可见。
i>freeze实现:
pg9.4之前freeze方法: 直接将符合条件的元组的t_xmin设置为2,回收原来的xid。但这样实现的问题是:一)当前可见的数据页需要全部扫描,带来大量的IO扫描;二)符合条件的元组需要更新xmin,造成大量脏页,带来大量IO pg9.4后对freeze优化: 不直接修改t_xmin,而是:一)只更新元组头结点的t_infomask为HEAP_XMIN_FROZEN,表示该元组已经被冻结过(frozen);二)有些插入操作,也可以直接将记录置为frozen,例如大批量的COPY数据,insert into等;三)如果整个page所有记录已经frozen,则在vm文件中标记为FROZEN,冻结清理会跳过该页,减少了IO扫描。
ii>freeze优化:
freeze是被动触发的,可以调节pg的一些参数优化freeze,更多时候提倡用户进行主动预测需要freeze的时机,选择合适的时间(比如pg负载较低的时间)主动执行vacuum freeze命令。目前已经有很多实现好的开源PostgreSQL vacuum freeze监控管理工具,比如flexible-freeze,能够:确定数据库的高峰和低峰期;在数据库低峰期创建一个cron job执行flexible_freeze.py;flexible_freeze.py会自动对具有最老XID的表进行vacuum freeze。
9,Standby数据库
1)概念
1>主备数据库
高可用:主数据库(Primary db,Master db)失败后,备数据库(Standby db)快速提升为Master db并提供服务。 高可靠性:Master bd和Standby db存在数据同步,从而提高数据的可靠性。通常是一台master db提供读写,然后把数据同步到量一台standby db(只读)。 Hot standby db:同步数据时可以提供只读服务的standby db(pg9.0提供)。反之为Warm standby db。
2>WAL日志文件
pg在数据目录的pg_wal子目录(10版本之前是pg_xlog目录)中始终维护一个WAL文件。 wal文件记录了db数据文件的每次改变,最初设计是为了db异常崩溃后,能够重放最后一次checkpoint之后的日志文件,把数据块推到最终的一致状态,避免数据丢失和不一致。 WAL文件的存在可以让备份数据块存在不一致的数据,通过重放WAL日志文件加以纠正,推到任意一个时间点,即基于时间点备份(PITR,Point-in-Time Recovery)。 对于standby db,只要应用wal日志足够快,就能保持与Master db一致的数据。把WAL日志传送到另一台机器的方法有两种:
通过WAL归档日志方法; standby db会落后master db一个wal文件。具体落后多长时间取决于master db生成一个wal文件的时间。流复制。(pg9.x版本之后) 有两种方式,同步方式,几乎没有延时。异步方式,落后时间取决于网络延迟和standby的i/o能力。
主备同步wal相关配置:
参数名说明优化方案
synchronous_commit如果双节点,设置为ON,如果是多副本,同步模式,建议设置为remote_write。如果磁盘性能很差,并且是OLTP业务。可以考虑设置为off降低COMMIT的RT,提高吞吐(设置为OFF时,可能丢失部分XLOG RECORD)
full_page_writes如果文件系统支持COW例如ZFS,则建议设置为OFF。 如果文件系统可以保证datafile block size的原子写,在对齐后也可以设置为OFF。
wal_writer_delaywal写的延迟缩短延迟,加快wal写的速度
wal_writer_flush_after
checkpoint_timeout不建议频繁做检查点,否则XLOG会产生很多的FULL PAGE WRITE(when full_page_writes=on)提高该值,降低FULL PAGE WRITE,较少XLOG,降低wal压力
max_wal_size建议等于SHARED BUFFER,或2倍。
min_wal_size建议是SHARED BUFFER的2分之一
wal_receiver_status_interval反馈给主节点自己已经接受( replies )到数据信息。减小,加快反馈速度
wal_buffers基于shared_buffers,shared_buffers/32增大,加快wal落盘速度
10,好用工具
1)PgBouncer
为pg提供的一个轻量级连接池工具。
2)Slony-I
基于触发器的两个pg的逻辑同步。
3)Bucardo
双向同步工具,可以实现pg的双(多)master方案。
4)pgpool-II
pg和客户端之间的中间件。
11,Postgres-XC
Postgres-XC是基于pg实现的真正的数据水平拆分的分布式数据库。
标签:
相关推荐:
精彩放送:
- []焦点讯息:ipo上市流程6大步骤和时间,有以下六个流程
- []每日播报!什么银行的信用卡最好办 信用卡最好办的是什么银行
- []焦点消息!前2月住宅均价涨4.1% 结束11连跌
- []天天快资讯丨政策效果显现 房地产回暖可期
- []环球消息!2023中国商业地产百强企业研究成果分析
- []当前视点!合肥楼市分化明显:一边60秒触发摇号,一边无人登记
- []2023中国房地产百强企业研究报告
- []天天消息!迈贝特再获殊荣!连续斩获“分布式光伏创新品牌”及“跟踪系统创新企业”两项大奖
- []美联储缩表是什么意思
- []亚洲硅业“易主”!光伏教父或套现百亿
- []今日看点:建设银行金卡,可以直接到网点办理
- []定增30亿!宝馨科技加码光伏
- []微动态丨余额宝提现到银行卡要手续费吗,不需要
- []每日讯息!地摊经济是什么
- []股市放假元旦节几天,三天
- []世界讯息:招商局置地:2022年实现营业收入298.71亿元
- []全球播报:超30家A股房企无一完成定增,新城控股“迎难而上”披露定增预案
- []世界速看:资源控股拟配发11.61亿股予Wealth Elite 将抵消1.16亿港元债务
- []【环球聚看点】房地产市场降幅明显收窄,仍处在调整阶段
- []每日观点:越秀地产:2022年实现营业收入约币724.2亿元
- []今头条!佳缘科技:公司不断加大科研投入,紧跟通信发展步伐
- []当前关注:清乾隆瓷胎画珐琅山水人物纹茶盅
- []保险费怎么算 保险费的计算公式是什么
- []怎么向银行贷款
- []每日看点!泰康人寿怎么样 寿康人寿好吗
- []天天热点评!个人贷款1万怎么贷
- []热议:银行融资什么意思,以银行为中介的资金融通活动
- []中国平安2022年末不动产投资规模2046亿 较年初下降0.8pps
- []越秀地产2022年新增土地37幅
- []熵基科技: 公司与微软的OpenAI的合作,处于合作接洽阶段
- []每日速看!小样是什么意思啊_小样是什么意思
- []今热点:越秀地产2022年核心净利润42.4亿元 同比上升2.1%
- []每日速看!微信支付优惠券哪里领
- []每日速读!什么是企业账户号,企业在银行开设的账户
- []什么是小天使基金
- []如何辨别假的人民币
- []世界时讯:三胎养老概念龙头股票有哪些,十大概念股名单一览
- []当前时讯:利和兴:3月14日公司高管侯卫峰减持公司股份合计8.41万股
- []环球最资讯丨金力泰:3月14日公司高管景总法减持公司股份合计5.65万股
- []奥士康:3月14日公司高管徐文静减持公司股份合计8.1万股
- []世界快资讯:中国消费反弹将利好欧洲股市,建议60/40配置消费股组合
- []天天报道:古鳌科技:3月14日公司高管陈崇军减持公司股份合计1.6万股
- []每日看点!分期车可以抵押贷款吗
- []天天快资讯:非农数据公布时间
- []环球热头条丨城建税怎么计算
- []全球快消息!金融衍生产品 金融的衍生产品指的是什么
- []环球快看:股票交易佣金 股票的交易佣金是多少
- []天天热门:港龙中国地产:2022年拥有人应占溢利不少于1.2亿 整体毛利率下滑
- []天天即时:或在年报披露后被实施退市风险警示 ST榕泰索赔案仍在诉讼时效内
- []同频共振聚合力 同心同向凝共识——内蒙古证监局组织开展3·15投资者保护主题教育活动
- []焦点报道:国联证券:大股东竞得民生证券30.3%股权对公司日常经营无实质影响
- []观天下!烟台黄渤海新区召开企业上市突破发展大会 力争2025年上市公司突破20余家
- []环球讯息:孚能科技:3月14日李盘忠、梁景洪减持公司股份合计2.66万股
- []当前聚焦:支付宝利率是多少2022,利率不是固定的
- []每日聚焦:主力资金流向怎么看,有以下四点
- []微信转账收费 微信转账要收费吗
- []股票解禁是什么意思
- []焦点信息:多方解读A股下跌原因 a股暴跌原因
- []天天快看:微信的零钱通和支付宝的余额宝哪个好_支付宝里的余额宝怎么赚钱
- []每日消息!双汇发展:如有相关计划,公司将按照有关规定进行披露
- []世界热点评!最新龙虎榜:机构买入N天23转超12亿,知名游资买入北方国际
- []看热讯:信用卡养卡技巧,有以下四点
- []中国银行定期一本通,以下两种方式可查余额
- []工商银行灵通卡和储蓄卡区别
- []买金条的好处与坏处 分别有三点
- []今日精选:天恒置业集团原党委书记、董事长刘海涛等2人接受审查调查
- []消息!格力地产:控股股东海投公司再质押1.2亿股
- []青岛金王:我公司没有在您所述的银行存款
- []焦点快看:厦门安居控股拟发行12亿元公司债 用于偿还银行借款
- []快看点丨东方国信:东方国信已连续多年保持国家级工业互联网双跨平台前列
- []麦格米特:截至2023年3月10日,公司股东人数为11,000+
- []全球今亮点!合肥城建2020年向工业控股增发1.8亿股限售期将延长6个月
- []环球聚焦:越秀地产公布2022年全年业绩 合同销售再创新高 股东应占净利润同比上升10.2%
- []看中了沃尔沃S90?0息0负担的凯迪拉克CT6更值得!
- []钠电量产元年!负极材料是成本突破点?
- []环球微动态丨基金的收益怎么算
- []天天滚动:什么是失业保险
- []养卡是什么意思
- []通讯!光伏发电政策情况及趋势分析
- []世界动态:电化学类储能主要包括哪些储能方式?
- []去银行办卡需要带什么证件
- []净利劲增300%,双良节能正在从光伏新秀变成老将
- []二手房贷款年限
- []全球热讯:两大煤炭龙头公布业绩:日赚亿元,却不及预期?
- []每日热门:远洋集团位列廊坊1-2月销售金额榜、面积榜第一
- []【环球聚看点】南山控股:控股子公司宝湾物流成功发行5亿元中票 利率3.63%
- []环球消息!京城佳业:2022年收入约为15.67亿元
- []全球新资讯:上海电气:转让子公司100%股权 预计产生税前净收益2.87亿元
- []【世界热闻】远洋集团位列天津成交TOP5 未来城揽获城市销冠
- []凤凰传媒:纸张价格下跌会对公司成本带来一定的积极影响
- []当前视点!汉宇集团:公司在硅谷银行没有存款。硅谷银行的暴雷对公司没有影响
- []中信银行年费多少
- []焦点精选!广信材料:接受信达证券等机构调研
- []国家储备金什么意思
- []伊朗成第二批出境团队游目的地“黑马”,多个旅行社首团售罄
- []环球新资讯:支付宝利率多少,有以下两点
- []天天报道:上市聆讯是什么意思国内上市的基本条件
- []我想贷款5万哪里好贷审批快
- []宁夏医学院是几本?宁夏医学院资料介绍?
- []天天速读:厦门建发集团15亿元公司债将付息 利率4.57%
- B站注册资本增幅400%至5亿 目前由陈睿全资持股
- 光源资本出任独家财务顾问 沐曦集成电路10亿元A轮融资宣告完成
- 巨轮智能2021年上半年营收11.24亿元 期内研发费用投入增长19.05%
- 红枣期货尾盘拉升大涨近6% 目前红枣市场总库存约30万吨
- 嘉银金科发布2021年Q2财报 期内净利润达1.27亿元同比增长208%
- 成都银行2021上半年净利33.89亿元 期内实现营收同比增长17.27亿元
- 汽车之家发布2021年第二季度业绩 期内新能源汽车品牌收入增长238%
- 中信银行上半年实现净利润290.31亿元 期末不良贷款余额706.82亿元
- 光伏概念掀起涨停潮交易价格创新高 全天成交额达1.29亿元
- 上半年生物药大增45% 关键财务指标好转营收账款持续下降
- 环球最新:烟台山公园在哪里?福州烟台山公园开放时间?
- 【环球新视野】豫园股份:复星集团所持3804万股解除质押 1.52亿股质押期延长
- 通常月季花几月开花?月季花品种有哪些?
- 双飞燕无线鼠标怎么连接?双飞燕无线鼠标的连接方法?
- 环球观热点:威奥股份:公司2022年年度报告将于2023年4月27日披露
- 世界动态:香雪制药:近期甲流发展势头迅猛,多地学校因甲流停课,医院接诊量也剧增
- 承德美食有哪些?承德美食介绍?
- 全球热推荐:何文田瑜一第1B期折实售价最低786.84万港元
- 世界观点:电信无线网卡怎么用?电信无线网卡的使用方法?
- 热点在线丨央行:2022年末我国金融业机构总资产为419.64万亿元 同比增长9.9%
- 全球热头条丨天箭科技:公司正在研发的新型相控阵天线可广泛应用于星载、机载、弹载产品中
- 讯息:陕西都市快报求助电话是多少?《都市快报》是什么节目?
- 今日热议:书包怎么装拉杆?连体式拉杆书包有哪些优缺点?
- 陆家嘴5亿元公司债将于3月27日本息兑付并摘牌 票面利率3.9%
- 许广平与鲁迅先生什么关系?许广平资料介绍?
- 当前快看:撕番什么意思?撕番怎么理解?
- 世界微动态丨Discuz!模板文件css.htm制作教程 Discuz!模板文件的简单讲解
- 环球热议:手机合约机和裸机有什么区别?合约机和裸机有什么好处?
- 在Ubuntu18.04、Deep终端中实现输入密码回显星号
- 天天报道:全国gdp排名2021年,各城市gdp排名一览
- 【全球聚看点】免费打谱软件 AnthemScore:免费的钢琴谱软件
- 速读:经济问题有哪些
- 【时快讯】李斯特简介及代表作:《匈牙利狂想曲》第二首
- 精选!交易成本包括
- 全球热门:应付账款会计分录怎么做
- 环球看点!荷兰旅游签证怎么办理?荷兰签证需要哪些材料?
- 在访问网页中弹出“脚本错误”的提示框 如何解决?
- 最新消息:k2386火车时刻表到天津站 K257在天津哪个站出发?
- 天天视点!北交所新股申购规则
- 世界简讯:微信占用内存太大怎么办?微信如何清理空间?
- 坚守“诚信兴商”之道,梧桐树保险经纪荣获“3·15诚信企业”荣誉称号
- 环球热资讯!至上月底4宗外地基金迁册来港申请已获批
- 美原油交易策略:油价剑指70关口,警惕破位风险,关注EIA数据
- 支付宝宁波银行快捷支付如何开通?开通的方法流程
- 安迪和小包总相爱的两个人 在一起只会让对方苦楚?
- 精彩看点:【生活百科】吸湿盒和除湿包哪个更好用?
- 焦点观察:魔兽世界之冰封王座秘籍 怎么进不去了?
- 全球信息:国际金价短线或跌向1890美元
- 【天天播资讯】3月15日渤海化学涨停分析:工业大麻,天津国企改革,石油化工概念热股
- 焦点关注:微信抢红包怎么抢最佳?从青铜级到王者级的操作招式
- 环球观天下!宇顺电子:截至2023年3月10日,公司股东户数为一万三千余户
- 【独家】什么是APM?什么是应用程序性能管理(APM)?
- 全球热文:String.format的用法(字符串格式化)
- 全球头条:大反弹!房价结束11连跌,住宅均价上涨4.1%,住宅销售面积增速大幅回升26.2个百分点
- 天天讯息:爱柯迪(600933)3月15日主力资金净买入609.60万元
- 世界关注:上海张江高科拟发行5.7亿元科技创新公司债 分为2个品种
- 环球观点:怎样安装安卓平板电脑软件?安装安卓平板电脑软件的注意事项有哪些?
- 天天日报丨粤华制药生产假药“加味藿香正气丸”被罚没40万
- 当前短讯!Rancher和KubeSphere哪个更友好?Rancher和KubeSphere的对比介绍
- 天天快看:3月15日三星新材涨停分析:白色家电,冷链,家电概念热股
- 全球消息!河北衡水:3月份起下调首套商业性住房贷款利率下限至3.8%
- 热推荐:国际金价小幅走低,通胀继续困扰FED,接下来看它的表现
- 今亮点!3月15日齐心集团涨停分析:优化生育(三孩),独角兽,腾讯概念股概念热股
- 每日视点!直通315|超千万元学区房交易过程中学位被占用 中介机构是否要担责?
- 全球今头条!【Stripe支付】国际版APP、Braine注册流程详解
- 动态:什么是ASP?一文带你揭开ASP神秘面纱
- 环球快讯:三年定期大额存款利率2022最新,各银行大额存款利率一览
- 热资讯!【风口研报】甲流“抬头”!关注检测、疫苗、药物等机会 辅助生殖板块也在风口!
- 什么叫车损险
- 世界速看:物价指数计算公式
- 【焦点热闻】公积金贷款利率2022最新利率表,各行公积金贷款利率一览
- 中国商业银行排名,各商业银行排名一览表
- 现货黄金交易策略:金价温和回调,关注美国零售销售数据
- 环球速讯:北京首旅集团拟发行上限10亿元中票 期限2+N年期
- 世界热门:中信建投国家电投新能源REIT发售首日认购金额295亿 认购或超1500亿元
- “盐田港集团”控股股东企业名称变更为“深圳港集团”
- 世界观焦点:石头科技将在本月发布年度旗舰扫地机器人新品
- 焦点热讯:湖北文旅6亿元超短期融资券完成发行 利率2.86%
- 每日动态!合锻智能:您可以将收件地址发送至邮箱xuqin@hfpress.com,公司安排人员邮寄
- 焦点热讯:合肥:购买非营运性新能源汽车最高可获5000元新车补贴
- 今日播报!爱婴室:截至2023年3月10日,公司股东人数为19100人
- 环球新消息丨供需双弱,锂价下跌或将延续
- 环球微资讯!丛麟科技:截至2023年3月10日,公司股东户数为16,123户
- 热讯:什么信号?聪明资金大举加仓创业板 这些ETF最吸金!龙头公司业绩亮眼
- 世界观察:公积金有封顶金额吗
- 每日头条!支付宝账户是什么 支付宝账户是指什么意思
- 当前快播:交通银行积分兑换商城在哪
- 中国石油加油卡如何办理
- 即时:什么是虚拟货币交易
- 2023年中国银行业保险业服务创新峰会成功举办,梧桐树荣获“消费者权益保护典型案例”奖
- 前2月房企业到位资金同比下降15.2%
- 前2月全国房地产开发投资同比下降5.7%
- 国家统计局谈房地产市场:还在调整阶段,有望逐步企稳
- 全球速讯:道道全:2022年三季度存货增加主要是因为茂名工厂投产后,菜籽存货增加
- 【报资讯】众信旅游:定制海岛婚礼旅拍产品一直是公司的重要主题产品之一
- 竞拍162次 无锡国联发展91.05亿元竞得民生证券34.71亿股股权
- 环球观热点:大摩:上调太古地产今明两年每股盈利预测各2%及7%
- 年利率公式 年利率怎么计算
- 环球看点!银行活期存款利率 什么是活期存款利率
- 环球微动态丨贷款是怎么贷,有以下三种方法
- 皓极热的背后:不是“激鄂”营销,也非饥饿营销!
- 看点:太原公租房可以转卖吗?
- 【全球时快讯】vma指标
- 刚兑是什么意思,刚性兑付
- 刷屏,每平米超百万,一套房总价超8家A股公司市值!优质慢牛股揭秘,机构预测业绩翻倍股仅3只
- 富瑞预期利率见顶 支持香港地产前景优于银行业的观点
- 国家统计局:目前房地产市场还是处在调整阶段 后期有望逐步企稳
- 天天最资讯丨一张图:黄金原油外汇股指"枢纽点+多空占比"一览(2023/03/15周三)
- 全球微速讯:投资、销售、资金全线反弹!楼市小阳春能持续多久?
- 全球今亮点!菲德医疗美容使用未经批准药品 被罚17.5万