PostgreSQL 当有多个索引可选时,优化器如何选择

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云原生数据库 PolarDB 分布式版,标准版 2核8GB
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 标签PostgreSQL , 索引 , 复合索引 , 选择 , 成本 , 优化器背景当一个表有很多索引时,并且一个QUERY可以使用到其中的多个索引时,数据库会如何做出选择?最终选择哪个,或者哪几个索引呢?《PostgreSQL 多查询条件,多个索引的选择算法与问题诊断方法》选择单个索引时,PATH可以选择index scan , index only scan, bitmap scan。

标签

PostgreSQL , 索引 , 复合索引 , 选择 , 成本 , 优化器


背景

当一个表有很多索引时,并且一个QUERY可以使用到其中的多个索引时,数据库会如何做出选择?最终选择哪个,或者哪几个索引呢?

《PostgreSQL 多查询条件,多个索引的选择算法与问题诊断方法》

选择单个索引时,PATH可以选择index scan , index only scan, bitmap scan。

选择多个索引时,PATH可以选择bitmap scan。

那么优化器会选择哪个,或者哪几个索引,又会选择index scan , index only scan还是 bitmap scan呢?

例子

1、创建4张表,5个字段,分别使用int2,int4,int8,text类型。

create table t1 (c1 int2, c2 int2, c3 int2, c4 int2, c5 int2);  
  
create table t2 (c1 int4, c2 int4, c3 int4, c4 int4, c5 int4);  
  
create table t3 (c1 int8, c2 int8, c3 int8, c4 int8, c5 int8);  
  
create table t4 (c1 text, c2 text, c3 text, c4 text, c5 text);  

2、写入测试数据1000万条,其中c3字段为常量

insert into t1 select random()*32767,random()*32767,random()*32767,1,random()*32767 from generate_series(1,10000000);  
  
insert into t2 select random()*2000000000,random()*2000000000,random()*2000000000,1,random()*2000000000 from generate_series(1,10000000);  
  
insert into t3 select random()*2000000000,random()*2000000000,random()*2000000000,1,random()*2000000000 from generate_series(1,10000000);  
  
insert into t4 select md5(random()::text),md5(random()::text),md5(random()::text),'a',md5(random()::text) from generate_series(1,10000000);  

3、创建若干索引

create index idx_t1_1 on t1(c1);  
create index idx_t1_2 on t1(c1,c2);  
create index idx_t1_3 on t1(c1,c2,c3);  
create index idx_t1_4 on t1(c4);  
  
create index idx_t2_1 on t2(c1);  
create index idx_t2_2 on t2(c1,c2);  
create index idx_t2_3 on t2(c1,c2,c3);  
create index idx_t2_4 on t2(c4);  
  
create index idx_t3_1 on t3(c1);  
create index idx_t3_2 on t3(c1,c2);  
create index idx_t3_3 on t3(c1,c2,c3);  
create index idx_t3_4 on t3(c4);  
  
create index idx_t4_1 on t4(c1);  
create index idx_t4_2 on t4(c1,c2);  
create index idx_t4_3 on t4(c1,c2,c3);  
create index idx_t4_4 on t4(c4);  

4、强制收集统计信息

vacuum analyze t1;  
vacuum analyze t2;  
vacuum analyze t3;  
vacuum analyze t4;  

数据库如何选择索引? - 现象

1、输入c1,c2,c3三个字段的等值过滤,作为条件,t1,t2,t3,t4分别选择了哪个索引?

t1选择了c1,c2,c3的合并索引,没有任何多余的filter

postgres=# explain select * from t1 where c1=1 and c2=1 and c3=1;  
                             QUERY PLAN                               
--------------------------------------------------------------------  
 Index Scan using idx_t1_3 on t1  (cost=0.43..2.66 rows=1 width=10)  
   Index Cond: ((c1 = 1) AND (c2 = 1) AND (c3 = 1))  
(2 rows)  

t2也选择了c1,c2,c3的合并索引,没有任何多余的filter

postgres=# explain select * from t2 where c1=1 and c2=1 and c3=1;  
                             QUERY PLAN                               
--------------------------------------------------------------------  
 Index Scan using idx_t2_3 on t2  (cost=0.43..2.66 rows=1 width=20)  
   Index Cond: ((c1 = 1) AND (c2 = 1) AND (c3 = 1))  
(2 rows)  

t3选择了c1,c2的合并索引,有多余的c3的filter

postgres=# explain select * from t3 where c1=1 and c2=1 and c3=1;  
                             QUERY PLAN                               
--------------------------------------------------------------------  
 Index Scan using idx_t3_2 on t3  (cost=0.43..2.66 rows=1 width=40)  
   Index Cond: ((c1 = 1) AND (c2 = 1))  
   Filter: (c3 = 1)  
(3 rows)  

t4选择了c1,c2的合并索引,有多余的c3的filter

postgres=# explain select * from t4 where c1='1' and c2='1' and c3='a';  
                             QUERY PLAN                                
---------------------------------------------------------------------  
 Index Scan using idx_t4_2 on t4  (cost=0.56..2.78 rows=1 width=134)  
   Index Cond: ((c1 = '1'::text) AND (c2 = '1'::text))  
   Filter: (c3 = 'a'::text)  
(3 rows)  

t1,t2,t3,t4的数据记录数,数据分布,SQL、索引都一样,为什么会有以上的选择性差异呢?

数据库如何选择索引? - 分析

1 索引大小分析

postgres=# \di+ idx_t*  
                          List of relations  
 Schema |   Name   | Type  |  Owner   | Table |  Size   | Description   
--------+----------+-------+----------+-------+---------+-------------  
 public | idx_t1_1 | index | postgres | t1    | 214 MB  |   
 public | idx_t1_2 | index | postgres | t1    | 214 MB  |   
 public | idx_t1_3 | index | postgres | t1    | 214 MB  |   
 public | idx_t1_4 | index | postgres | t1    | 214 MB  |   
 public | idx_t2_1 | index | postgres | t2    | 214 MB  |   
 public | idx_t2_2 | index | postgres | t2    | 214 MB  |   
 public | idx_t2_3 | index | postgres | t2    | 301 MB  |   
 public | idx_t2_4 | index | postgres | t2    | 214 MB  |   
 public | idx_t3_1 | index | postgres | t3    | 214 MB  |   
 public | idx_t3_2 | index | postgres | t3    | 301 MB  |   
 public | idx_t3_3 | index | postgres | t3    | 387 MB  |   
 public | idx_t3_4 | index | postgres | t3    | 214 MB  |   
 public | idx_t4_1 | index | postgres | t4    | 563 MB  |   
 public | idx_t4_2 | index | postgres | t4    | 911 MB  |   
 public | idx_t4_3 | index | postgres | t4    | 1266 MB |   
 public | idx_t4_4 | index | postgres | t4    | 214 MB  |   
(16 rows)  

有没有觉得很奇怪呢?

t1表,从1个字段到3个字段的合并索引,索引大小都一样!!!!!!!而且都与t3表单个字段一样大。

t2表,一个字段与2个字段的索引大小一样大!!!!!2个字段的与T3表的1个字段一样大。3个字段的与T3表的2个字段一样大。

t3表,容量方面看起来很正常。

t4表,c4单个字段的索引,与T3表的单个字段的索引一样大。

看起来好像是这样的:

INDEX TUPLE占用8个字节的倍数。(可能是对齐的考虑)

2 索引内部结构分析

《深入浅出PostgreSQL B-Tree索引结构》

1、采用pageinspect插件,可以看到索引内部的内容

create extension pageinspect;  

2、查看索引叶子节点的内容

postgres=# select * from bt_metap('idx_t1_1');  
 magic  | version | root | level | fastroot | fastlevel   
--------+---------+------+-------+----------+-----------  
 340322 |       2 |  290 |     2 |      290 |         2  
(1 row)  
  
postgres=# select * from bt_page_items('idx_t1_1',290) limit 5;  
 itemoffset |   ctid   | itemlen | nulls | vars |          data             
------------+----------+---------+-------+------+-------------------------  
          1 | (3,1)    |       8 | f     | f    |   
          2 | (289,1)  |      16 | f     | f    | 54 01 00 00 00 00 00 00  
          3 | (575,1)  |      16 | f     | f    | a9 02 00 00 00 00 00 00  
          4 | (860,1)  |      16 | f     | f    | fe 03 00 00 00 00 00 00  
          5 | (1145,1) |      16 | f     | f    | 52 05 00 00 00 00 00 00  
(5 rows)  
  
postgres=# select * from bt_page_items('idx_t1_1',289) limit 5;  
 itemoffset |  ctid   | itemlen | nulls | vars |          data             
------------+---------+---------+-------+------+-------------------------  
          1 | (572,1) |      16 | f     | f    | a9 02 00 00 00 00 00 00  
          2 | (286,1) |       8 | f     | f    |   
          3 | (287,1) |      16 | f     | f    | 55 01 00 00 00 00 00 00  
          4 | (288,1) |      16 | f     | f    | 56 01 00 00 00 00 00 00  
          5 | (291,1) |      16 | f     | f    | 57 01 00 00 00 00 00 00  
(5 rows)  
  
postgres=# select * from bt_page_items('idx_t1_1',287) limit 5;  
 itemoffset |    ctid     | itemlen | nulls | vars |          data             
------------+-------------+---------+-------+------+-------------------------  
          1 | (38155,112) |      16 | f     | f    | 56 01 00 00 00 00 00 00  
          2 | (20034,36)  |      16 | f     | f    | 55 01 00 00 00 00 00 00  
          3 | (20183,9)   |      16 | f     | f    | 55 01 00 00 00 00 00 00  
          4 | (20250,124) |      16 | f     | f    | 55 01 00 00 00 00 00 00  
          5 | (20957,123) |      16 | f     | f    | 55 01 00 00 00 00 00 00  
(5 rows)  
  
postgres=# select * from t1 where ctid='(38155,112)';  
 c1  |  c2   |  c3   | c4 |  c5     
-----+-------+-------+----+-------  
 342 | 18698 | 24394 |  1 | 27763  
(1 row)  
  
postgres=# select to_hex(342);  
 to_hex   
--------  
 156  
(1 row)  
  
对应56 01 00 00 00 00 00 00  
  
倒过来看 01 56。  

确实有一个现象和前面的描述一样: INDEX TUPLE占用8个字节的倍数。

虽然是INT2的类型,本质上只占用2字节,但是实际上INDEX TUPLE占用了8个字节。

3、查看T2表,1个字段的索引。现象也和前面的描述一样: INDEX TUPLE占用8个字节的倍数。

postgres=# select * from bt_metap('idx_t2_1');  
 magic  | version | root | level | fastroot | fastlevel   
--------+---------+------+-------+----------+-----------  
 340322 |       2 |  290 |     2 |      290 |         2  
(1 row)  
  
postgres=# select * from bt_page_items('idx_t2_1',290) limit 5;  
 itemoffset |   ctid   | itemlen | nulls | vars |          data             
------------+----------+---------+-------+------+-------------------------  
          1 | (3,1)    |       8 | f     | f    |   
          2 | (289,1)  |      16 | f     | f    | 0f 5c 3c 01 00 00 00 00  
          3 | (575,1)  |      16 | f     | f    | 8f 8e 7a 02 00 00 00 00  
          4 | (860,1)  |      16 | f     | f    | c1 f8 b7 03 00 00 00 00  
          5 | (1145,1) |      16 | f     | f    | 46 12 f7 04 00 00 00 00  
(5 rows)  
  
postgres=# select * from bt_page_items('idx_t2_1',289) limit 5;  
 itemoffset |  ctid   | itemlen | nulls | vars |          data             
------------+---------+---------+-------+------+-------------------------  
          1 | (572,1) |      16 | f     | f    | 8f 8e 7a 02 00 00 00 00  
          2 | (286,1) |       8 | f     | f    |   
          3 | (287,1) |      16 | f     | f    | 5b 8a 3d 01 00 00 00 00  
          4 | (288,1) |      16 | f     | f    | 36 a2 3e 01 00 00 00 00  
          5 | (291,1) |      16 | f     | f    | 4b ca 3f 01 00 00 00 00  
(5 rows)  
  
postgres=# select * from bt_page_items('idx_t2_1',572) limit 5;  
 itemoffset |    ctid    | itemlen | nulls | vars |          data             
------------+------------+---------+-------+------+-------------------------  
          1 | (3798,12)  |      16 | f     | f    | 3d b3 7b 02 00 00 00 00  
          2 | (48744,46) |      16 | f     | f    | 8f 8e 7a 02 00 00 00 00  
          3 | (40279,76) |      16 | f     | f    | 1a 8f 7a 02 00 00 00 00  
          4 | (53268,39) |      16 | f     | f    | a9 8f 7a 02 00 00 00 00  
          5 | (16540,92) |      16 | f     | f    | 35 90 7a 02 00 00 00 00  
(5 rows)  
  
postgres=# select * from t2 where ctid='(3798,12)';  
    c1    |    c2     |    c3    | c4 |     c5       
----------+-----------+----------+----+------------  
 41661245 | 940376658 | 41196565 |  1 | 1467443120  
(1 row)  
  
postgres=# select to_hex(41661245);  
 to_hex    
---------  
 27bb33d  
(1 row)  
  
对应3d b3 7b 02 00 00 00 00  
  
倒过来看 02 7b b3 3d。  

4、查看T2表,3个字段的索引。现象也和前面的描述一样: INDEX TUPLE占用8个字节的倍数。

postgres=# select * from bt_metap('idx_t2_3');  
 magic  | version | root | level | fastroot | fastlevel   
--------+---------+------+-------+----------+-----------  
 340322 |       2 |  209 |     2 |      209 |         2  
(1 row)  
  
postgres=# select * from bt_page_items('idx_t2_3',209) limit 5;  
 itemoffset |  ctid   | itemlen | nulls | vars |                      data                         
------------+---------+---------+-------+------+-------------------------------------------------  
          1 | (3,1)   |       8 | f     | f    |   
          2 | (208,1) |      24 | f     | f    | a8 2c a1 00 78 82 d4 3d 55 1b a6 67 00 00 00 00  
          3 | (413,1) |      24 | f     | f    | a8 9d 42 01 3c fe ab 6b e7 69 81 1c 00 00 00 00  
          4 | (617,1) |      24 | f     | f    | c8 f7 e5 01 eb cd b6 31 49 90 14 6f 00 00 00 00  
          5 | (821,1) |      24 | f     | f    | e7 b6 86 02 9c 1e 63 65 c4 c3 06 48 00 00 00 00  
(5 rows)  
  
postgres=# select * from bt_page_items('idx_t2_3',208) limit 5;  
 itemoffset |  ctid   | itemlen | nulls | vars |                      data                         
------------+---------+---------+-------+------+-------------------------------------------------  
          1 | (410,1) |      24 | f     | f    | a8 9d 42 01 3c fe ab 6b e7 69 81 1c 00 00 00 00  
          2 | (205,1) |       8 | f     | f    |   
          3 | (206,1) |      24 | f     | f    | b5 ef a1 00 bf b0 c5 14 94 4f ae 63 00 00 00 00  
          4 | (207,1) |      24 | f     | f    | 1b b1 a2 00 0a f5 c6 33 c4 09 e3 12 00 00 00 00  
          5 | (210,1) |      24 | f     | f    | 34 81 a3 00 82 74 a7 42 fe d6 33 06 00 00 00 00  
(5 rows)  
  
postgres=# select * from bt_page_items('idx_t2_3',410) limit 5;  
 itemoffset |    ctid     | itemlen | nulls | vars |                      data                         
------------+-------------+---------+-------+------+-------------------------------------------------  
          1 | (61769,131) |      24 | f     | f    | a6 6b 43 01 83 ab a4 04 0c a4 9e 29 00 00 00 00  
          2 | (44927,154) |      24 | f     | f    | a8 9d 42 01 3c fe ab 6b e7 69 81 1c 00 00 00 00  
          3 | (24587,3)   |      24 | f     | f    | e3 9d 42 01 4a 9f 46 25 b9 d2 8e 47 00 00 00 00  
          4 | (29996,51)  |      24 | f     | f    | be 9e 42 01 66 33 fd 03 8c 8c 39 2c 00 00 00 00  
          5 | (4032,73)   |      24 | f     | f    | 5c 9f 42 01 ea 4d b1 01 1d af 88 32 00 00 00 00  
(5 rows)  
  
postgres=# select * from t2 where ctid='(61769,131)';  
    c1    |    c2    |    c3     | c4 |     c5       
----------+----------+-----------+----+------------  
 21195686 | 77900675 | 698262540 |  1 | 1522991839  
(1 row)  
  
postgres=# select to_hex(21195686);  
 to_hex    
---------  
 1436ba6  
(1 row)  
  
postgres=# select to_hex(77900675);  
 to_hex    
---------  
 4a4ab83  
(1 row)  
  
postgres=# select to_hex(698262540);  
  to_hex    
----------  
 299ea40c  
(1 row)  
  
对应a6 6b 43 01 83 ab a4 04 0c a4 9e 29 00 00 00 00  
  
每个字段占用4字节,倒过来看 01 43 6b a6。04 a4 ab 83。29 9e a4 0c。   

但是这些个索引选择有什么关系吗?

本身没什么关系,但是由于这样出现了一个问题,索引本身占用的大小,在评估成本时也在成本计算环节之一。

HINT , 成本对比

最后数据库选什么索引,其实还是取决于COST。

每个PATH的COST都会算一遍,哪个最低选哪个。

使用hint来强制使用某个索引,这样就能对比出COST到底差多少?

postgres=# set pg_hint_plan.debug_print =on;  
SET  
postgres=# set pg_hint_plan.enable_hint=on;  
SET  
  
postgres=# set pg_hint_plan.message_level =log;  
SET  
postgres=# set client_min_messages =log;  
SET  

以t4表为例

postgres=# explain (analyze,verbose,timing,costs,buffers) /*+ IndexScan(t4 idx_t4_3) */ select * from t4 where c1='1' and c2='1' and c3='a';  
LOG:  available indexes for IndexScan(t4): idx_t4_3  
LOG:  pg_hint_plan:  
used hint:  
IndexScan(t4 idx_t4_3)  
not used hint:  
duplication hint:  
error hint:  
  
                                                      QUERY PLAN                                                        
----------------------------------------------------------------------------------------------------------------------  
 Index Scan using idx_t4_3 on public.t4  (cost=0.69..2.91 rows=1 width=134) (actual time=0.012..0.012 rows=0 loops=1)  
   Output: c1, c2, c3, c4, c5  
   Index Cond: ((t4.c1 = '1'::text) AND (t4.c2 = '1'::text) AND (t4.c3 = 'a'::text))  
   Buffers: shared hit=5  
 Planning time: 0.188 ms  
 Execution time: 0.027 ms  
(6 rows)  
postgres=# explain (analyze,verbose,timing,costs,buffers) /*+ IndexScan(t4 idx_t4_2) */ select * from t4 where c1='1' and c2='1' and c3='a';  
LOG:  available indexes for IndexScan(t4): idx_t4_2  
LOG:  pg_hint_plan:  
used hint:  
IndexScan(t4 idx_t4_2)  
not used hint:  
duplication hint:  
error hint:  
  
                                                      QUERY PLAN                                                        
----------------------------------------------------------------------------------------------------------------------  
 Index Scan using idx_t4_2 on public.t4  (cost=0.56..2.78 rows=1 width=134) (actual time=0.012..0.012 rows=0 loops=1)  
   Output: c1, c2, c3, c4, c5  
   Index Cond: ((t4.c1 = '1'::text) AND (t4.c2 = '1'::text))  
   Filter: (t4.c3 = 'a'::text)  
   Buffers: shared hit=5  
 Planning time: 0.212 ms  
 Execution time: 0.027 ms  
(7 rows)  

很显然,数据库评估出来选择idx_t4_2的成本为2.78,使用idx_t4_3的成本为2.91。

理所当然,选择了idx_t4_2。虽然它多了一次filter。

那么为什么idx_t4_2的成本更低呢?

 public | idx_t4_2 | index | postgres | t4    | 911 MB  |   
 public | idx_t4_3 | index | postgres | t4    | 1266 MB |   

1、走idx_t4_2索引时,评估出来扫描的数据块比idx_t4_3更少,虽然它多了filter,但是filter引入的开销在 RANDOM PAGE SCAN面前小得多(并且实际上这里没有filter的成本,因为c1,c2两个条件下去后评估出来的ROWS=0 select * from t4 where c1='1' and c2='1';)。

2、走idx_t4_3索引时,评估出来不需要filter,但是这个索引比idx_t4_2占用的空间大,按比例划分时,算了更多的random page SCAN 成本。即使没有额外的filter,成本也比idx_t4_2更高。

PS:

这样的评估算法应该还有优化的空间,因为实际上两个索引的LEVEL是一样的。

postgres=# select * from bt_metap('idx_t2_2');  
 magic  | version | root | level | fastroot | fastlevel   
--------+---------+------+-------+----------+-----------  
 340322 |       2 |  290 |     2 |      290 |         2  
(1 row)  
  
postgres=# select * from bt_metap('idx_t2_3');  
 magic  | version | root | level | fastroot | fastlevel   
--------+---------+------+-------+----------+-----------  
 340322 |       2 |  209 |     2 |      209 |         2  
(1 row)  

以上,使用idx_t2_2和idx_t2_3扫描的INDEX PAGE数实际上是一样的。

小结

PostgreSQL 采用CBO的优化器模型,哪个PATH成本低,就使用哪个PATH。

在有多个索引可以使用时,实际上数据库会计算每一种的成本,哪种成本低,选择哪个。

影响成本的因素很多:

算子设置,选择性,扫描成本,INDEX TUPLE过滤成本,HEAP TUPLE过滤成本。

成本是综合的结果。

思考:

select * from tbl where c1=1 and c2=1 and c3=1 and c4=1;  
  
idx(c1,c2)  
  
idx(c2,c3)  
  
idx(c4,c3,c1)  

选哪个索引?需要考虑什么因素?

提示:

多列统计信息,统计信息,多列条件合并选择性、索引大小、RANDOM SCAN成本,SEQ SCAN成本,FILTER的成本,成本算子参数,优化器开关等。

参考

《深入浅出PostgreSQL B-Tree索引结构》

《PostgreSQL 10 黑科技 - 自定义统计信息》

src/backend/optimizer/path/costsize.c

《PostgreSQL 多查询条件,多个索引的选择算法与问题诊断方法》

《PostgreSQL 自定义函数表达式选择性评估算法 - Statistics, Cardinality, Selectivity, Estimate》

《PostgreSQL 优化器行评估算法》

《关键时刻HINT出彩 - PG优化器的参数优化、执行计划固化CASE》

《优化器成本因子校对 - PostgreSQL explain cost constants alignment to timestamp》

《优化器成本因子校对(disk,ssd,memory IO开销精算) - PostgreSQL real seq_page_cost & random_page_cost in disks,ssd,memory》

https://www.postgresql.org/docs/11/static/planner-stats-details.html

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
26天前
|
关系型数据库 分布式数据库 数据库
PolarDB常见问题之加了索引但是查询没有使用如何解决
PolarDB是阿里云推出的下一代关系型数据库,具有高性能、高可用性和弹性伸缩能力,适用于大规模数据处理场景。本汇总囊括了PolarDB使用中用户可能遭遇的一系列常见问题及解答,旨在为数据库管理员和开发者提供全面的问题指导,确保数据库平稳运行和优化使用体验。
|
2月前
|
SQL 算法 关系型数据库
PolarDB-X的XPlan索引选择
对于数据库来说,正确的选择索引是基本的要求,选错索引轻则导致查询缓慢,重则导致数据库整体不可用。PolarDB-X存在多种不同的索引,局部索引、全局索引、列存索引、归档表索引。本文主要介绍一种CN上的局部索引算法:XPlan索引选择。
125705 13
PolarDB-X的XPlan索引选择
|
3月前
|
关系型数据库 MySQL 分布式数据库
PolarDB MySQL企业版与标准版功能对比:如何选择适合您的版本?
随着数字化时代的到来,企业对于数据处理的需求越来越高,而数据库作为数据处理的核心,其性能和成本成为了企业关注的焦点。阿里云全新推出的PolarDB MySQL企业版和标准版,以全新的架构和优化,为企业提供了高性能、低成本的数据库解决方案。但在功能上,这两个版本有很多差异,我们该如何选择呢?
51 2
|
7月前
|
Oracle 关系型数据库 数据库
PostgreSQL和Oracle两种数据库有啥区别?如何选择?
PostgreSQL和Oracle两种数据库有啥区别?如何选择?
191 0
|
3月前
|
关系型数据库 定位技术 索引
在关系型数据库中,常见的索引种类包括哪些
在关系型数据库中,常见的索引种类包括哪些
484 0
|
6月前
|
关系型数据库 MySQL 分布式数据库
PolarDB MySQL版重磅推出的列存索引(
PolarDB MySQL版重磅推出的列存索引(
335 1
|
6月前
|
存储 关系型数据库 OLAP
polardb和ob的区别是什么,如何选择?
polardb和ob的区别是什么,如何选择?
|
6月前
|
关系型数据库 Go 数据库
《提高查询速度:PostgreSQL索引实用指南》
《提高查询速度:PostgreSQL索引实用指南》
321 0
|
6月前
|
SQL 缓存 关系型数据库
PolarDB-X 混沌测试实践:如何衡量数据库索引选择能力
随着PolarDB分布式版的不断演进,功能不断完善,新的特性不断增多,整体架构扩大的同时带来了测试链路长,出现问题前难发现,出现问题后难排查等等问题。原有的测试框架已经难以支撑实际场景的复杂模拟测试。因此,我们实现了一个基于业务场景面向优化器索引选择的混沌查询实验室,本文之后简称为CEST(complex environment simulation test)。
|
6月前
|
存储 关系型数据库 MySQL
如何选择最适合你的数据库解决方案:PostgreSQL VS MySQL 技术选型对比
如何选择最适合你的数据库解决方案:PostgreSQL VS MySQL 技术选型对比
204 1

相关产品

  • 云原生数据库 PolarDB