PostgreSQL——分區表

分區表

  • 一、分區表的意義
  • 二、傳統分區表
    • 2.1、繼承表
    • 2.2、創建分區表
    • 2.3、使用分區表
    • 2.4、查詢父表還是子表
    • 2.5、constraint_exclusion參數
    • 2.6、添加分區
    • 2.7、刪除分區
    • 2.8、分區表相關查詢
    • 2.9、傳統分區表注意事項
  • 三、內置分區表
    • 3.1、創建分區表
    • 3.2、使用分區表
    • 3.3、內置分區表原理
    • 3.4、添加分區
    • 3.5、刪除分區
    • 3.6、更新分區數據
    • 3.7、內置分區表注意事項

一、分區表的意義

分區表主要有以下優勢 :

  • 當查詢或更新一個分區上的大部分數據時,對分區進行索引掃描代價很大,然而,在分區上使用順序掃描能提升性能 。
  • 當需要刪除一個分區數據時,通過 DROP TABLE 刪除一個分區,遠比 DELETE 刪除數據高效,特別適用于日志數據場景。
  • 由于一個表只能存儲在一個表空間上,使用分區表后,可以將分區放到不同的表空間上,例如可以將系統很少訪問的分區放到廉價的存儲設備上,也可以將系統常訪問的分區存儲在高速存儲上。

二、傳統分區表

傳統分區表是通過繼承和觸發器方式實現的,其實現過程步驟多,非常復雜,需要定義父表、定義子表、定義子表約束、創建子表索引、創建分區插入、刪除、修改函數和觸發器等,可以說是在普通基礎上手動實現的分區表。在介紹傳統分區表之前先介紹繼承,繼承是傳統分區表的重要組成部分。

2.1、繼承表

PostgreSQL提供繼承表,簡單地說是首先定義一張父表,之后可以創建子表繼承父表,下面通過一個簡單的例子來理解。

創建一張日志模型表tbl_log:

create table tbl_log(id int4,create_date date,log_type text
);create table tbl_log_sql(sql text
) inherits(tbl_log);

通過inherits(tbl_log)表示表tbl_log_sql繼承表tbl_log,子表可以定義額外的字段,以上定義了sql為額外字段,其它字段則繼承父表tbl_log,查看tbl_log_sql表結構如下:
在這里插入圖片描述

父表和子表都可以插入數據,接著分別在父表和子表中插入一條數據,如下所示:

insert into tbl_log
values(1, '2017-08-26', null);insert into tbl_log_sql
values(2, '2017-08-27', null, 'select 2');

這時如果查詢父表tbl_log會顯示兩表的記錄,如下所示:

select * from tbl_log;

在這里插入圖片描述

盡管查詢父表會將子表的記錄數也列出,但子表自定義的字段沒有顯示,如果想確定數據來源于哪張表,可通過以下SQL查看表的OID,如下所示:

select tableoid, *
from tbl_log;

在這里插入圖片描述

tableoid是表的隱藏字段,表示表的OID,可以通過pg_class系統關聯找到表名,如下所示:

select p.relname, c.*
from tbl_log c, pg_class p
where c.tableoid = p.oid;

如果只想查詢父表的數據,需在父表名稱前加上關鍵字ONLY,如下所示:

select * 
from only tbl_log;

在這里插入圖片描述

因此,對于UPDATE、DELETE、SELECT操作,如果父表名稱前面沒有加上ONLY,則會對父表和所有子表進行DML操作,如下所示:

delete from tbl_log;select count(*) 
from tbl_log;

在這里插入圖片描述

2.2、創建分區表

傳統分區表創建過程主要包括以下幾個步驟:

  1. 創建父表,如果父表上定義了約束,子表會繼承,因此除非是全局約束,否則不應該在父表上定義約束,另外,父表不應該寫入數據。
  2. 通過inherits方式創建繼承表,也稱之為子表或分區,子表的字段定義應該和父表保持一致。
  3. 給所有子表創建約束,只有滿足約束條件的數據才能寫入對應分區,注意分區約束值范圍不要有重疊。
  4. 給所有子表創建索引,由于繼承操作不會繼承父表上的索引,因此索引需要手工創建。
  5. 在父表上定義insert、delete、update觸發器,將SQL分發到對應分區,這步可選,因為應用可以根據分區規則定位到對應分區進行DML操作。
  6. 啟用constraint_exclusion參數,如果這個參數設置成off,則父表上的SQL性能會降低,后面會通過示例解釋這個參數。

以上六個步驟是創建傳統分區表的主要步驟,接下來通過一個示例演示創建一張范圍分區表,并且定義年月子表存儲月數據。

首先創建父表:

create table log_ins(id serial,user_id int4,create_time timestamp(0) without time zone
);

創建13張子表:

create table log_ins_history(check(create_time < '2017-01-01')
) inherits(log_ins);create table log_ins_history_201701(check(create_time >= '2017-01-01' and create_time < '2017-02-01')
) inherits(log_ins);create table log_ins_history_201702(check(create_time >= '2017-02-01' and create_time < '2017-03-01')
) inherits(log_ins);create table log_ins_history_201703(check(create_time >= '2017-03-01' and create_time < '2017-04-01')
) inherits(log_ins);create table log_ins_history_201704(check(create_time >= '2017-04-01' and create_time < '2017-05-01')
) inherits(log_ins);create table log_ins_history_201705(check(create_time >= '2017-05-01' and create_time < '2017-06-01')
) inherits(log_ins);create table log_ins_history_201706(check(create_time >= '2017-06-01' and create_time < '2017-07-01')
) inherits(log_ins);create table log_ins_history_201707(check(create_time >= '2017-07-01' and create_time < '2017-08-01')
) inherits(log_ins);create table log_ins_history_201708(check(create_time >= '2017-08-01' and create_time < '2017-09-01')
) inherits(log_ins);create table log_ins_history_201709(check(create_time >= '2017-09-01' and create_time < '2017-10-01')
) inherits(log_ins);create table log_ins_history_201710(check(create_time >= '2017-10-01' and create_time < '2017-11-01')
) inherits(log_ins);create table log_ins_history_201711(check(create_time >= '2017-11-01' and create_time < '2017-12-01')
) inherits(log_ins);create table log_ins_history_201712(check(create_time >= '2017-12-01' and create_time < '2018-01-01')
) inherits(log_ins);

給子表創建索引:

create index idx_his_ctime on log_ins_history 
using btree (create_time);create index idx_log_ins_201701_ctime on log_ins_history_201701 
using btree (create_time);create index idx_log_ins_201702_ctime on log_ins_history_201702
using btree (create_time);create index idx_log_ins_201703_ctime on log_ins_history_201703
using btree (create_time);create index idx_log_ins_201704_ctime on log_ins_history_201704
using btree (create_time);create index idx_log_ins_201705_ctime on log_ins_history_201705
using btree (create_time);create index idx_log_ins_201706_ctime on log_ins_history_201706
using btree (create_time);create index idx_log_ins_201707_ctime on log_ins_history_201707
using btree (create_time);create index idx_log_ins_201708_ctime on log_ins_history_201708
using btree (create_time);create index idx_log_ins_201709_ctime on log_ins_history_201709
using btree (create_time);create index idx_log_ins_201710_ctime on log_ins_history_201710
using btree (create_time);create index idx_log_ins_201711_ctime on log_ins_history_201711
using btree (create_time);create index idx_log_ins_201712_ctime on log_ins_history_201712
using btree (create_time);

由于父表上不存儲數據,可以不用在父表上創建索引。

創建觸發器函數,設置數據插入父表時的路由規則,如下所示:

create or  replace function log_ins_insert_trigger()returns triggerlanguage plpgsql
as $function$
beginif (NEW.create_time < '2017-01-01') theninsert into log_ins_history VALUES(NEW.*);elsif (NEW.create_time >= '2017-01-01' and NEW.create_time < '2017-02-01') theninsert into log_ins_history_201701 VALUES(NEW.*);elsif (NEW.create_time >= '2017-02-01' and NEW.create_time < '2017-03-01') theninsert into log_ins_history_201702 VALUES(NEW.*);elsif (NEW.create_time >= '2017-03-01' and NEW.create_time < '2017-04-01') theninsert into log_ins_history_201703 VALUES(NEW.*);elsif (NEW.create_time >= '2017-04-01' and NEW.create_time < '2017-05-01') theninsert into log_ins_history_201704 VALUES(NEW.*);elsif (NEW.create_time >= '2017-05-01' and NEW.create_time < '2017-06-01') theninsert into log_ins_history_201705 VALUES(NEW.*);elsif (NEW.create_time >= '2017-06-01' and NEW.create_time < '2017-07-01') theninsert into log_ins_history_201706 VALUES(NEW.*);elsif (NEW.create_time >= '2017-07-01' and NEW.create_time < '2017-08-01') theninsert into log_ins_history_201707 VALUES(NEW.*);elsif (NEW.create_time >= '2017-08-01' and NEW.create_time < '2017-09-01') theninsert into log_ins_history_201708 VALUES(NEW.*);elsif (NEW.create_time >= '2017-09-01' and NEW.create_time < '2017-10-01') theninsert into log_ins_history_201709 VALUES(NEW.*);elsif (NEW.create_time >= '2017-10-01' and NEW.create_time < '2017-11-01') theninsert into log_ins_history_201710 VALUES(NEW.*);elsif (NEW.create_time >= '2017-11-01' and NEW.create_time < '2017-12-01') theninsert into log_ins_history_201711 VALUES(NEW.*);elsif (NEW.create_time >= '2017-12-01' and NEW.create_time < '2018-01-01') theninsert into log_ins_history_201712 VALUES(NEW.*);else raise exception 'create_time out of range. Fix the log_ins_insert trigger() function!';end if;return null;
end;
$function$;

函數中的NEW.*是指要插入的數據行,在父表上定義插入觸發器:

create trigger insert_log_ins_trigger
before insert
on log_ins
for each row
execute procedure log_ins_insert_trigger();

觸發器創建完成后,向父表log_ins插入數據時,會執行觸發器并觸發函數log_ins_insert_trigger()將表數據插入到相應的分區中。DELETE、UPDATE觸發器和函數創建過程和INSERT方式類似,傳統分區表的創建步驟已全部完成。

2.3、使用分區表

向父表log_ins插入測試數據,并驗證數據是否插入對應分區:

insert into log_ins(user_id, create_time)
select round(10000000*random()), generate_series('2016-12-01'::date, '2017-12-01'::date, '1 minute');

這里通過隨機生成數據插入,數據如下所示:

select * 
from log_ins limit 5;

在這里插入圖片描述

查看父表數據,發現父表沒有數據;

select count(*) from only log_ins;

在這里插入圖片描述

select count(*) from log_ins;

在這里插入圖片描述

查看子表數據:

select min(create_time), max(create_time)
from log_ins_history_201701;

在這里插入圖片描述

這說明子表里可查到數據,查看子表大小:
在這里插入圖片描述

由此可見數據都已經插入到子表里。

2.4、查詢父表還是子表

假如我們檢索2017-01-01這一天的數據,我們可以查詢父表,也可以直接查詢子表,兩者性能上是否有差異?

查詢父表的執行計劃如下:

explain analyze select *
from log_ins 
where create_time > '2017-01-01' and create_time < '2017-01-02';

在這里插入圖片描述

從以上執行計劃看出在分區log_ins_history_201701上進行了索引掃描,接著查看直接查詢子表log_ins_history_201701的執行計劃:

explain analyze select *
from log_ins_history_201701
where create_time > '2017-01-01' and create_time < '2017-01-02';

在這里插入圖片描述

從以上執行計劃看出,直接查詢子表更快,如果并發量上去的話,這個差異將更明顯,因此實際生產過程中,對于傳統分區表分區方式,不建議應用訪問父表,而是直接訪問子表,也許有人會問,應用如何定位到訪問哪張子表呢?可以根據預先的分區約束定義,上面的例子是根據時間范圍分區,name應用可以根據時間來判斷查詢哪張子表,當然,以上是根據分表表分區鍵查詢的場景,如果根據非分區鍵查詢則會掃描分區表的所有分區。

2.5、constraint_exclusion參數

constraint_exclusion參數用來控制優化器是否根據表上的約束來優化查詢,參數為以下值:

  • on:所有表都通過約束優化查詢
  • off:所有表都不通過約束優化查詢
  • partition:只對繼承表和UNION ALL子查詢通過檢索約束來優化查詢

簡單地說,如果設置成on或partition,查詢父表時優化器會根據子表上的約束判斷檢索哪些子表,而不要掃描所有子表,從而提升查詢性能。

2.6、添加分區

添加分區屬于分區表維護的常規操作之一,比如歷史表范圍分區到期之前需要擴分區,log ins表為日志表,每個分區存儲當月數據,假如分區快到期了,可通過以下SQL擴分區,首先創建子表,如下所示:

create table log_ins_history_201801(check(create_time >= '2018-01-01' and create_time < '2018-02-01')
) inherits(log_ins);

之后創建相關索引:

create index idx_log_ins_201801_ctime 
on log_ins_history_201801 using btree(create_time);

然后刷新觸發器函數log_ins_insert_trigger(0,添加相應代碼,將符合路由規則的數據插入新分區,詳見之前定義的這個函數,這步完成后,添加分區操作完成,可通過d+log_ins命令查看log_ins的所有分區。

這種方法比較直接,創建分區時就將分區繼承到父表,如果中間步驟有錯可能對生產系統帶來影響,比較推薦的做法是將以上操作分解成以下幾個步驟,降低對生產系統的影響,如下所示:

-- 創建分區
create table log_ins_history_201802(like log_ins including all
);-- 添加約束
alter table log_ins_history_201802 
add constraint log_ins_history_201802_create_time_check
check (create_time >= '2018-02-01' and create_time < '2018-03-01');-- 刷新觸發器函數log_ins_insert_trigger()-- 所有步驟完成后,將新分區log_ins_201802繼承到父表log_ins
alter table log_ins_hisroty_201802 inherit log_ins;

以上方法是將新分區所有操作完成后,再將分區繼承到父表,降低了生產系統添加分區操作的風險,當然,在生產系統添加分區前建議在測試環境事先演練一把。

2.7、刪除分區

分區表的一個重要優勢是對于大表的管理上十分方便,例如需要刪除歷史數據時可以直接刪除一個分區,這比DELETE方式效率高了多個數量級,傳統分區表刪除分區通常有兩種方法,第一種方法是直接刪除分區,如下所示:

drop table log_ins_201802;

就像刪除普通表一樣刪除分區即可,當然刪除分區前需再三確認是否需要備份數據;另一種比較推薦的刪除分區方法是先將分區的繼承關系去掉,如下所示:

alter table log_ins_history_201802 no inherit log_ins;

執行以上命令后,log ins201802分區不再屬于分區表log_ins的分區,但log_ins_history_201802表依然保留可供查詢,這種方式相比方法一提供了一個緩沖時間,屬于比較穩妥的刪除分區方法,因為在拿掉子表繼承關系后,只要沒刪除這個表,還可以使子表重新繼承父表。

2.8、分區表相關查詢

分區表創建完成后,如何查看分區表定義、分區表分區信息呢?比較常用的方法是通過\d元命令,如下所示:
在這里插入圖片描述

以上信息顯示了表 log_ ins有 14 個分區,并且創 建了觸發器 ,觸發器函數為 log_ins_insert_ trigger (),如 果想列出分區名稱可通過\d+ log_ins 元命令列出 。

另一種列出分區表分區信息方法是通過SQL命令:

select nmsp_parent.nspname as parent_schema,parent.relname as parent,nmsp_child.nspname as child_schema,child.relname as child_schema
from pg_inherits join pg_class parent
on pg_inherits.inhparent = parent.oid join pg_class child
on pg_inherits.inhrelid = child.oid join pg_namespace nmsp_parent
on nmsp_parent.oid = parent.relnamespace join pg_namespace nmsp_child
on nmsp_child.oid = child.relnamespace
where parent.relname = 'log_ins';

在這里插入圖片描述

pg_inherits系統表記錄了子表和父表之間的繼承關系,通過以上查詢列出指定分區表的分區。如果想查看一個庫中有哪些分區表,并顯示這些分區表的分區數量,可通過以下SQL查詢:

select nspname, relname, count(*) as partition_num
from pg_class c, pg_namespace n, pg_inherits i
where c.oid = i.inhparent 
and c.relnamespace = n.oid
and c.relhassubclass
and c.relkind in ('r', 'p')
group by 1,2 
order by partition_num desc;

在這里插入圖片描述
以上結果顯示當前庫中有兩個分區表,log_ins分區表有14個分區,tbl_log分區表只有一個分區。

2.9、傳統分區表注意事項

傳統分區表的使用有以下注意事項:

  • 當往父表上插入數據時,需事先在父表上創建路由函數和觸發器,數據才會根據分區鍵路由規則插入到對應分區中,目前僅支持范圍分區和列表分區。
  • 分區表上的索引、約束需要使用單獨的命令創建,目前沒有辦法一次性自動在所有分區上創建索引、約束。
  • 父表和子表允許單獨定義主鍵,因此父表和子表可能存在重復的主鍵記錄,目前不支持在分區表上定義全局主鍵。
  • UPDATE時不建議更新分區鍵數據,特別是會使數據從一個分區移動到另一分區的場景,可通過更新觸發器實現,但會帶來管理上的成本。
  • 性能方面:根據本節的測試數據和測試場景,傳統分區表根據非分區鍵查詢相比普通表性能差距較大,因為這種場景下分區表會掃描所有分區;根據分區鍵查詢相比普通表性能有小幅降低,而查詢分區表子表性能相比普通表略有提升;

三、內置分區表

PostgreSQL10一個重量級新特性是支持內置分區表,用戶不需要預先在父表上定義INSERT、DELETE、UPDATE觸發器,對父表的DML操作會自動路由到相應分區,相比傳統分區表大幅度降低了維護成本,目前僅支持范圍分區和列表分區。

3.1、創建分區表

創建分區表的主要語法包含兩部分:創建主表和創建分區。
創建主表語法如下:

create table table_name (...)
[ partition by {range | list}  ({column_name | expression})] 

創建主表時須指定分區方式,可選的分區方式為RANGE范圍分區或LIST列表分區,并指定字段或表達式作為分區鍵。

創建分區的語法如下:

create table table_name() partition of parent_table for values partition_bound_spec

創建分區時必須指定是哪張表的分區,同時指定分區策略partition bound spec,如果是范圍分區,partition bound spec須指定每個分區分區鍵的取值范圍,如果是列表分區
partition_bound_spec,需指定每個分區的分區鍵值。

PostgreSQL10創建內置分區表主要分為以下幾個步驟:

  1. 創建父表,指定分區鍵和分區策略。
  2. 創建分區,創建分區時須指定分區表的父表和分區鍵的取值范圍,注意分區鍵的范圍不要有重疊,否則會報錯。
  3. 在分區上創建相應索引,通常情況下分區鍵上的索引是必須的,非分區鍵的索引可根據實際應用場景選擇是否創建。

接下來通過創建范圍分區的示例來演示內置分區表的創建過程,首先創建一張范圍分區表,表名為log_par,如下所示:

create table log_par (id serial,user_id int4,create_time timestamp(0) without time zone
) partition by range(create_time);

表log par指定了分區策略為范圍分區,分區鍵為create time字段。創建分區,并設置分區的分區鍵取值范圍,如下所示:

create table log_par_his partition of log_par 
for values from ('2016-01-01') to ('2017-01-01');create table log_par_201701 partition of log_par 
for values from ('2017-01-01') to ('2017-02-01');create table log_par_201702 partition of log_par 
for values from ('2017-02-01') to ('2017-03-01');create table log_par_201703 partition of log_par 
for values from ('2017-03-01') to ('2017-04-01');create table log_par_201704 partition of log_par 
for values from ('2017-04-01') to ('2017-05-01');create table log_par_201705 partition of log_par 
for values from ('2017-05-01') to ('2017-06-01');create table log_par_201706 partition of log_par 
for values from ('2017-06-01') to ('2017-07-01');create table log_par_201707 partition of log_par 
for values from ('2017-07-01') to ('2017-08-01');create table log_par_201708 partition of log_par 
for values from ('2017-08-01') to ('2017-09-01');create table log_par_201709 partition of log_par 
for values from ('2017-09-01') to ('2017-10-01');create table log_par_201710 partition of log_par 
for values from ('2017-10-01') to ('2017-11-01');create table log_par_201711 partition of log_par 
for values from ('2017-11-01') to ('2017-12-01');create table log_par_201712 partition of log_par 
for values from ('2017-12-01') to ('2018-01-01');

注意分區的分區鍵范圍不要有重疊,定義分區鍵范圍實質上給分區創建了約束。

給所有分區的分區鍵創建索引,如下所示:

create index idx_log_par_his_ctime
on log_par_his using btree(create_time);create index idx_log_par_201701_ctime
on log_par_201701 using btree(create_time);create index idx_log_par_201702_ctime
on log_par_201702 using btree(create_time);create index idx_log_par_201703_ctime
on log_par_201703 using btree(create_time);create index idx_log_par_201704_ctime
on log_par_201704 using btree(create_time);create index idx_log_par_201705_ctime
on log_par_201705 using btree(create_time);create index idx_log_par_201706_ctime
on log_par_201706 using btree(create_time);create index idx_log_par_201707_ctime
on log_par_201707 using btree(create_time);create index idx_log_par_201708_ctime
on log_par_201708 using btree(create_time);create index idx_log_par_201709_ctime
on log_par_201709 using btree(create_time);create index idx_log_par_201710_ctime
on log_par_201710 using btree(create_time);create index idx_log_par_201711_ctime
on log_par_201711 using btree(create_time);create index idx_log_par_201712_ctime
on log_par_201712 using btree(create_time);

以上三步完成了內置分區表的創建。

3.2、使用分區表

向分區表插入數據:

insert into log_par(user_id, create_time)
select round(100000 * random()), generate_series('2016-12-01'::date, '2017-12-01'::"date", '1 minute');

查看表數據:

select count(*)
from log_par;

在這里插入圖片描述

select count(*)
from only log_par;

在這里插入圖片描述

從以上結果可以看出,父表log par沒有存儲任何數據,數據存儲在分區中,通過分區大小也可以證明這一點,如下所示:
在這里插入圖片描述

3.3、內置分區表原理

內置分區表原理實際上和傳統分區表一樣,也是使用繼承方式,分區可稱為子表,通過以下查詢很明顯看出表log par和其分區是繼承關系:

select nmsp_parent.nspname as parent_schema,parent.relname as parent,nmsp_child.nspname as child_schema,child.relname as child_schema
from pg_inherits join pg_class parent
on pg_inherits.inhparent = parent.oid join pg_class child
on pg_inherits.inhrelid = child.oid join pg_namespace nmsp_parent
on nmsp_parent.oid = parent.relnamespace join pg_namespace nmsp_child
on nmsp_child.oid = child.relnamespace
where parent.relname = 'log_par';

在這里插入圖片描述

3.4、添加分區

添加分區的操作 比較簡單,例如給 log_par 增加一個分區,如下所示 :

create table log_par_201801 partition of log_par
for values from ('2018-01-01') to ('2018-02-01');

之后給分區創建索引,如下所示 :

create index idx_log_par_201801_ctime 
on log_par_201801 using btree(create_time);

3.5、刪除分區

刪除分區有兩種方法,第一種方法通過 DROP 分區的方式來刪除,如下所示 :

drop table log_par_201801;

D ROP 方式直接將分 區 和分 區數據刪除,刪除前需確 認分區數據是否需要備份,避免數據丟失;另 一種推薦的方法是解綁分區, 如下所示 :

alter table log_par detach partition log_par_201801;

綁分區只是將分區 和 父表間 的關系斷開 ,分區和分區數據依然保留 ,這種方式比較穩妥,如果后續需要恢復這個分區,通過連接分區方式恢復分區即可,如下所示 :

alter table log_par attach partition log_par_201801 for values from ('2018-01-01') to ('2018-02-01');

連接分區時需要指定分區上的約束 。

3.6、更新分區數據

內置分區 表 UPDAT E 操作目前不支持新記錄跨分區的情況, 也就是說只允許分區 內的更新 , 例如以下 SQL 會報錯:

update log_par set create_time = '2017-02-02 01:01:01' 
where user_id = 16965492;

以上 user_id 等于 16965492 的記錄位于 log_par_201701 分區,將這條記錄的 create_time 更新為 ’ 2017-02-02 01 : 01:01 ’由于違反了當前分區的約束將報錯,如果更新的數據不違反當前分區的約束則可正常更新數據,如下所示:

update log_par set create_time = '2017-01-01 01:01:01' 
where user_id = 16965492;

目前內置分區表的這一 限制對于日志表影響不大,對于業務表有一定影響,使用時需注意 。

3.7、內置分區表注意事項

  • 當往父表上插入數據時,數據會自動根據分區鍵路由規則插入到分區中,目前僅支持范圍分區和列表分區。
  • 分區表上的索引、約束需使用單獨的命令創建,目前沒有辦法一次性自動在所有分區上創建索引、約束。
  • 內置分區表不支持定義(全局)主鍵,在分區表的分區上創建主鍵是可以的。
  • 內置分區表的內部實現使用了繼承。
  • 如果UPDATE語句的新記錄違反當前分區鍵的約束則會報錯,UPDAET語句的新記錄目前不支持跨分區的情況。
  • 性能方面:根據本節的測試場景,內置分區表根據非分區鍵查詢相比普通表性能差距較大,因為這種場景分區表的執行計劃會掃描所有分區;根據分區鍵查詢相比普通表性能有小幅降低,而查詢分區表子表性能相比普通表略有提升。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/96850.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/96850.shtml
英文地址,請注明出處:http://en.pswp.cn/web/96850.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux任務調度全攻略

Linux下的任務調度分為兩類&#xff0c;系統任務調度和用戶任務調度。系統任務調度&#xff1a;系統周期性所要執行的工作&#xff0c;比如寫緩存數據到硬盤、日志清理等。在/etc目錄下有一個crontab文件&#xff0c;這個就是系統任務調度的配置文件。/etc/crontab文件包括下面…

回溯算法通關秘籍:像打怪一樣刷題

&#x1f680; 回溯算法通關秘籍&#xff1a;像打怪一樣刷題&#xff01; 各位同學&#xff0c;今天咱們聊聊 回溯算法&#xff08;Backtracking&#xff09;。它聽起來玄乎&#xff0c;但其實就是 “暴力搜索 剪枝” 的優雅版。 打個比方&#xff1a;回溯就是在迷宮里探險&am…

嵌入式Linux常用命令

&#x1f4df; 核心文件與目錄操作pwd-> 功能: 打印當前工作目錄的絕對路徑。-> 示例: pwd -> 輸出 /home/user/projectls [選項] [目錄]-> 功能: 列出目錄內容。-> 常用選項:-l: 長格式顯示&#xff08;詳細信息&#xff09;-a: 顯示所有文件&#xff08;包括隱…

深入理解 Linux 內核進程管理

在 Linux 系統中&#xff0c;進程是資源分配和調度的基本單位&#xff0c;內核對進程的高效管理直接決定了系統的性能與穩定性。本文將從進程描述符的結構入手&#xff0c;逐步剖析進程的創建、線程實現與進程終結的完整生命周期&#xff0c;帶您深入理解 Linux 內核的進程管理…

ACP(三):讓大模型能夠回答私域知識問題

讓大模型能夠回答私域知識問題 未經過特定訓練答疑機器人&#xff0c;是無法準確回答“我們公司項目管理用什么工具”這類內部問題。根本原因在于&#xff0c;大模型的知識來源于其訓練數據&#xff0c;這些數據通常是公開的互聯網信息&#xff0c;不包含任何特定公司的內部文檔…

使用Xterminal連接Linux服務器

使用Xterminal連接Linux服務器&#xff08;VMware虛擬機&#xff09;的步驟如下&#xff0c;前提是虛擬機已獲取IP&#xff08;如 192.168.31.105&#xff09;且網絡互通&#xff1a; 一、準備工作&#xff08;服務器端確認&#xff09;確保SSH服務已安裝并啟動 Linux服務器需要…

ChatBot、Copilot、Agent啥區別

以下內容為AI生成ChatBot&#xff08;聊天機器人&#xff09;、Copilot&#xff08;副駕駛&#xff09;和Agent&#xff08;智能體/代理&#xff09;是AI應用中常見的三種形態&#xff0c;它們在人機交互、自動化程度和任務處理能力上有著顯著的區別。特征維度ChatBot (聊天機器…

2025 年大語言模型架構演進:DeepSeek V3、OLMo 2、Gemma 3 與 Mistral 3.1 核心技術剖析

編者按&#xff1a; 在 Transformer 架構誕生八年之際&#xff0c;我們是否真的見證了根本性的突破&#xff0c;還是只是在原有設計上不斷打磨&#xff1f;今天我們為大家帶來的這篇文章&#xff0c;作者的核心觀點是&#xff1a;盡管大語言模型在技術細節上持續優化&#xff0…

基于Matlab GUI的心電信號QRS波群檢測與心率分析系統

心電信號&#xff08;Electrocardiogram, ECG&#xff09;是臨床診斷心臟疾病的重要依據&#xff0c;其中 QRS 波群的準確檢測對于心率分析、心律失常診斷及自動化心電分析系統具有核心意義。本文設計并實現了一套基于 MATLAB GUI 的心電信號處理與分析系統&#xff0c;集成了數…

1臺SolidWorks服務器能帶8-10人并發使用

在工業設計和機械工程領域&#xff0c;SolidWorks作為主流的三維CAD軟件&#xff0c;其服務器部署方案直接影響企業協同效率。通過云飛云共享云桌面技術實現多人并發使用SolidWorks時&#xff0c;實際承載量取決于硬件配置、網絡環境、軟件優化等多維度因素的綜合作用。根據專業…

String、StringBuilder和StringBuffer的區別

目錄一. String&#xff1a;不可變的字符串二.StringBuilder&#xff1a;可變字符串三.StringBuffer&#xff1a;線程安全的可變字符串四.總結在 Java 開發中&#xff0c;字符串處理是日常編碼中最頻繁的操作之一。String、StringBuilder 和 StringBuffer 這三個類雖然都用于操…

Power Automate List Rows使用Fetchxml查詢的一個bug

看一段FetchXML, 這段查詢在XRMtoolbox中的fech test工具里執行完全ok<fetch version"1.0" mapping"logical" distinct"true" no-lock"false"> <entity name"new_projectchange"> <link-entity name"sy…

Letta(MemGPT)有狀態AI代理的開源框架

1. 項目概述Letta&#xff08;前身為 MemGPT&#xff09;是一個用于構建有狀態AI代理的開源框架&#xff0c;專注于提供長期記憶和高級推理能力。該項目是MemGPT研究論文的實現&#xff0c;引入了"LLM操作系統"的概念用于內存管理。核心特點有狀態代理&#xff1a;具…

除了ollama還有哪些模型部署方式?多樣化模型部署方式

在人工智能的浪潮中&#xff0c;模型部署是釋放其強大能力的關鍵一環。大家都知道ollama&#xff0c;它在模型部署領域有一定知名度&#xff0c;操作相對簡單&#xff0c;受到不少人的青睞。但其實&#xff0c;模型部署的世界豐富多樣&#xff0c;今天要給大家介紹一款工具&…

Linux系統學習之進階命令匯總

文章目錄一、系統信息1.1 查看系統信息&#xff1a;uname1.2 查看主機名&#xff1a;hostname1.3 查看cpu信息&#xff1a;1.4 當前已加載的內核模塊: lsmod1.5 查看磁盤空間使用情況: df1.6 管理磁盤分區: fdisk1.7 查看目錄或文件磁盤使用情況: du1.8 查看I/O使用情況: iosta…

算法面試(2)------休眠函數sleep_for和sleep_until

操作系統&#xff1a;ubuntu22.04 IDE:Visual Studio Code 編程語言&#xff1a;C11 算法描述 這兩個函數都定義在 頭文件中&#xff0c;屬于 std::this_thread 命名空間&#xff0c;用于讓當前線程暫停執行一段時間。函數功能sleep_for(rel_time)讓當前線程休眠一段相對時間&…

貪心算法應用:5G網絡切片問題詳解

Java中的貪心算法應用&#xff1a;5G網絡切片問題詳解 1. 5G網絡切片問題概述 5G網絡切片是將物理網絡劃分為多個虛擬網絡的技術&#xff0c;每個切片可以滿足不同業務需求&#xff08;如低延遲、高帶寬等&#xff09;。網絡切片資源分配問題可以抽象為一個典型的優化問題&…

Android WorkManager的概念和使用

1. WorkManager基礎與核心概念 1.1 WorkManager概述 WorkManager是Android Jetpack架構組件庫的核心成員&#xff0c;專為管理可靠的后臺任務而設計。它提供了一套統一的API&#xff0c;用于調度需保障執行的延遲型異步任務&#xff08;如數據同步、日志上傳&#xff09;&…

容器使用卷

1.創建一個卷并讓容器掛載該卷1.創建一個卷[roothost1 ~]# docker volume create test-vol test-vol2.列出本地 Docker 主機上的卷[roothost1 ~]# docker volume ls DRIVER VOLUME NAME local test-vol3.查看該卷的詳細信息[roothost1 ~]# docker volume inspect test-v…

高數基礎知識(下)②

文章目錄七、微分方程7.3 高階線性微分方程7.3.1 線性微分方程的解的結構7.3.2 常系數齊次線性微分方程7.3.3 常系數非齊次線性微分方程八、多元函數微分學8.1 偏導數8.2 全微分8.3 基本定理8.4 復合函數微分法8.5 隱函數微分法8.6 多元函數的極值8.6.1 無條件極值8.6.2 條件極…