当前位置: 首页 > news >正文

openGauss真的比PostgreSQL差了10年?

前不久写了MogDB针对PostgreSQL的兼容性文章,我在文中提到针对PostgreSQL而言,MogDB兼容性还是不错的,其中也给出了其中一个能源客户之前POC的迁移报告数据。

But很快我发现总有人回留言喷我,而且我发现每次喷的这帮人是根本不看文章内容的,完全就是看了标题就开喷,真是一喷为快!

针对如此多的后台留言,这里为提炼一下,同时我也来尝试“诡辩”一下!

MogDB是基于openGauss,而openGauss是基于PG9.2,现在PG都16了,最差了这么多代,你们还好意思说?

首先我要说下,针对是这个想法的这些有网友,你们真的看了文章内容吗?原生pg是多进程架构,而魔改之后的openGauss是线程架构,架构都不一样了呢,毫不夸张的说,基本上是完全不同的两款数据库产品了。

因此,就谈不上什么版本差了很多代的说法了呢。

那么如果说基于openGauss迭代的MogDB具具备了PG新版本所具有的一些功能,你们又该如何评价呢?

这里我就特意挑选几个小的点!

MogDB支持全局索引而PG不支持

记得前几天PG界的第一红网德哥就吐槽说,PG不支持全局索引。当时我看了之后,我心里一阵纳闷!

不支持全局索引的数据库,这tm的能用吗?这不搞笑的吗?

首先我给大家看下MogDB对于分区表的全局索引支持情况,废话不多说,直接上测试结果:

[omm2@mogdb1 ~]$ gsql -r -d test -U roger
Password for user roger: 
gsql ((MogDB 5.0.7 build c4707384) compiled at 2024-05-24 10:51:53 commit 0 last mr 1804 )
Non-SSL connection (SSL connection is recommended when requiring high-security)
Type "help" for help.

test=> CREATE TABLE list_list
test-> (
test(>     month_code VARCHAR2 ( 30 ) NOT NULL ,
test(>     dept_code  VARCHAR2 ( 30 ) NOT NULL ,
test(>     user_no    VARCHAR2 ( 30 ) NOT NULL ,
test(>     sales_amt  int
test(> )
test-> PARTITION BY LIST (month_code) SUBPARTITION BY LIST (dept_code)
test-> (
test(>   PARTITION p_201901 VALUES ( '201902' )
test(>   (
test(>     SUBPARTITION p_201901_a VALUES ( '1' ),
test(>     SUBPARTITION p_201901_b VALUES ( '2' )
test(>   ),
test(>   PARTITION p_201902 VALUES ( '201903' )
test(>   (
test(>     SUBPARTITION p_201902_a VALUES ( '1' ),
test(>     SUBPARTITION p_201902_b VALUES ( '2' )
test(>   )
test(> );
CREATE TABLE
test=> insert into list_list values('201902''1''1', 1);
INSERT 0 1
test=> insert into list_list values('201902''2''1', 1);
INSERT 0 1
test=> insert into list_list values('201902''1''1', 1);
INSERT 0 1
test=> insert into list_list values('201903''2''1', 1);
INSERT 0 1
test=> insert into list_list values('201903''1''1', 1);
INSERT 0 1
test=> insert into list_list values('201903''2''1', 1);
INSERT 0 1
test=> create index idx_list_list on list_list(user_no) global;
CREATE INDEX
test=> explain select * from list_list where user_no=1;
                                  QUERY PLAN                                  
------------------------------------------------------------------------------
 Partition Iterator  (cost=0.00..14.57 rows=2 width=238)
   Iterations: 2, Sub Iterations: 4
   Selected Partitions:  1..2
   Selected Subpartitions:  1:ALL, 2:ALL
   ->  Partitioned Seq Scan on list_list  (cost=0.00..14.57 rows=2 width=238)
         Filter: ((user_no)::bigint = 1)
(6 rows)

test=> \di+
                                                     List of relations
 Schema |          Name           |          Type          | Owner |      Table       |    Size    | Storage | Description 
--------+-------------------------+------------------------+-------+------------------+------------+---------+-------------
 public | index_prune_tt01        | index                  | omm2  | prune_tt01       | 64 kB      |         | 
 public | table_1188398_2_pk      | index                  | omm2  | table_1188398_2  | 16 kB      |         | 
 roger  | idx_list_list           | global partition index | roger | list_list        | 16 kB      |         | 
 roger  | idx_test01_objectid     | index                  | roger | test01           | 245 MB     |         | 
 roger  | idx_test01_owner        | index                  | roger | test01           | 248 MB     |         | 
 roger  | t2_pkey                 | index                  | roger | t2               | 8192 bytes |         | 
 roger  | test_incresort_1_id_idx | index                  | roger | test_incresort_1 | 301 MB     |         | 
(7 rows)

大家可以看到这个分区的创建与法基本上跟Oracle一致,哪怕是二级分区,也支持创建global index的。

接下来我们看看PostgreSQL 13是否支持在分区表上创建Global Index。

postgres_5432@mogdb3 bin]$ ./psql
psql (13.2)
Type "help" for help.

postgres=# select version();
                                                version                                                 
---------------------------------------------------------------------------------------------------------
PostgreSQL 13.2 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44), 64-bit
(1 row)

postgres=#   CREATE TABLE list_list
postgres-#  (
postgres(#      month_code VARCHAR2 ( 30 ) NOT NULL ,
postgres(#      dept_code  VARCHAR2 ( 30 ) NOT NULL ,
postgres(#      user_no    VARCHAR2 ( 30 ) NOT NULL ,
postgres(#      sales_amt  int
postgres(#  )
postgres-#  PARTITION BY LIST (month_code) SUBPARTITION BY LIST (dept_code)
postgres-#  (
postgres(#    PARTITION p_201901 VALUES ( '201902' )
postgres(#    (
postgres(#      SUBPARTITION p_201901_a VALUES ( '1' ),
postgres(#      SUBPARTITION p_201901_b VALUES ( '2' )
postgres(#    ),
postgres(#    PARTITION p_201902 VALUES ( '201903' )
postgres(#    (
postgres(#      SUBPARTITION p_201902_a VALUES ( '1' ),
postgres(#      SUBPARTITION p_201902_b VALUES ( '2' )
postgres(#    )
postgres(#  );
ERROR:  syntax error at or near "SUBPARTITION"
LINE 8:  PARTITION BY LIST (month_code) SUBPARTITION BY LIST (dept_c...
                                       ^
postgres=#   
postgres=# CREATE TABLE measurement (
postgres(#     city_id         int not null,
postgres(#     logdate         date not null,
postgres(#     peaktemp        int,
postgres(#     unitsales       int
postgres(# ) PARTITION BY RANGE (logdate);
CREATE TABLE
postgres=
postgres=
postgres=# create table measurement_2022_1 partition of measurement
postgres-# for values from ('2022-01-01') to ('2022-02-01');
CREATE TABLE
postgres=
postgres=#  create table measurement_2022_2 partition of measurement
postgres-# for values from ('2022-02-01') to ('2022-03-01');
CREATE TABLE
postgres=
postgres=#  create table measurement_2022_3 partition of measurement
postgres-#  for values from ('2022-03-01') to ('2022-04-01');
CREATE TABLE
postgres=
postgres=# create index idx_measurement_date on measurement(logdate) global;
ERROR:  syntax error at or near "global"
LINE 1: ...e index idx_measurement_date on measurement(logdate) global;
                                                               ^
postgres=# create index idx_measurement_date on measurement(logdate);
CREATE INDEX

postgres=# insert into measurement(city_id,logdate,peaktemp,unitsales)  values(1,'2022-01-01',1,1);
INSERT 0 1
postgres=# insert into measurement(city_id,logdate,peaktemp,unitsales)  values(2,'2022-02-01',2,2);
INSERT 0 1
postgres=# insert into measurement(city_id,logdate,peaktemp,unitsales)  values(3,'2022-03-01',3,3);
INSERT 0 1
postgres=# \di+
                                                        List of relations
Schema |              Name              |       Type        |  Owner   |       Table        | Persistence |  Size   | Description 
--------+--------------------------------+-------------------+----------+--------------------+-------------+---------+-------------
public | idx_measurement_date           | partitioned index | postgres | measurement        | permanent   | 0 bytes | 
public | measurement_2022_1_logdate_idx | index             | postgres | measurement_2022_1 | permanent   | 16 kB   | 
public | measurement_2022_2_logdate_idx | index             | postgres | measurement_2022_2 | permanent   | 16 kB   | 
public | measurement_2022_3_logdate_idx | index             | postgres | measurement_2022_3 | permanent   | 16 kB   | 
(4 rows)

postgres=
ostgres=# explain select * from measurement where logdate > '2022-02-01';
                                            QUERY PLAN                                              
-----------------------------------------------------------------------------------------------------
Append  (cost=8.93..59.46 rows=1234 width=16)
  ->  Bitmap Heap Scan on measurement_2022_2 measurement_1  (cost=8.93..26.65 rows=617 width=16)
        Recheck Cond: (logdate > '2022-02-01'::date)
        ->  Bitmap Index Scan on measurement_2022_2_logdate_idx  (cost=0.00..8.78 rows=617 width=0)
              Index Cond: (logdate > '2022-02-01'::date)
  ->  Bitmap Heap Scan on measurement_2022_3 measurement_2  (cost=8.93..26.65 rows=617 width=16)
        Recheck Cond: (logdate > '2022-02-01'::date)
        ->  Bitmap Index Scan on measurement_2022_3_logdate_idx  (cost=0.00..8.78 rows=617 width=0)
              Index Cond: (logdate > '2022-02-01'::date)
(9 rows)

Time: 0.792 ms
postgres=# select * from measurement where logdate > '2022-02-01';
city_id |  logdate   | peaktemp | unitsales 
---------+------------+----------+-----------
      3 | 2022-03-01 |        3 |         3
(1 row)

Time: 0.491 ms

这是什么鬼?实际上我们可以看到PG的分区创建方式是有所区别的,简单的讲,其子分区已经是一个独立的表了,独立的文件。

不过从原理上来讲,我认为没有全局索引,还是一定程度上会影响查询性能,虽然local index其实也足够用了。

这个给大家举个例子,记得2014年去给某头部快递公司做数据库优化时(用的是Oracle exdata),发现一个访问非常高频的大表上的索引创建就不合理。

可能之前DBA是为了维护方便,索引几乎都是清一色的local分区,然而后面发现SQL的逻辑读非常高,在双11来临之前改成global index之后,逻辑读降低了数倍。当然最后系统CPU也降低了很多。

PG16新增的几个json函数,MogDB已经支持了

第二小的点是Postsql16新增的几个json处理函数,实际上MogDB 早就支持了。

大家可以参考pg的官方文档:https://www.postgresql.org/docs/16/release-16.html

[omm2@mogdb1 bin]$ gsql -r
gsql ((MogDB 5.0.7 build c4707384) compiled at 2024-05-24 10:51:53 commit 0 last mr 1804 )
Non-SSL connection (SSL connection is recommended when requiring high-security)
Type "help" for help.

MogDB=# \c dbm
Non-SSL connection (SSL connection is recommended when requiring high-security)
You are now connected to database "dbm" as user "omm2".
dbm=
dbm=# select json_array(1,'a','b',true,null);
        json_array         
---------------------------
 [1, "a""b"true, null]
(1 row)

dbm=#  CREATE TEMP TABLE foo1 (serial_num int, name text, type text);
CREATE TABLE
dbm=# INSERT INTO foo1 VALUES (847001,'t15','GE1043');
INSERT 0 1
dbm=# INSERT INTO foo1 VALUES (847002,'t16','GE1043');
INSERT 0 1
dbm=# INSERT INTO foo1 VALUES (847003,'sub-alpha','GESS90');
INSERT 0 1
dbm=# SELECT json_arrayagg(type) from foo1;
         json_arrayagg          
--------------------------------
 ["GE1043""GE1043""GESS90"]
(1 row)


dbm=# select json_object('{a,b,"a b c"}', '{a,1,1}');
              json_object              
---------------------------------------
 {"a" : "a""b" : "1""a b c" : "1"}
(1 row)

dbm=# select serial_num,JSON_OBJECTAGG(name,type) from foo1 group by serial_num;
 serial_num |     json_objectagg      
------------+-------------------------
     847003 | {"sub-alpha""GESS90"}
     847001 | {"t15""GE1043"}
     847002 | {"t16""GE1043"}
(3 rows)

dbm=

上述提到的几个函数,实际上我在PG13.2上测试发现是不支持的。

[postgres_5432@mogdb3 bin]$ ./psql
psql (13.2)
Type "help" for help.

postgres=# select json_array(1,'a','b',true,null);
ERROR:  function json_array(integer, unknown, unknown, boolean, unknown) does not exist
LINE 1: select json_array(1,'a','b',true,null);
               ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
postgres=#     
postgres=
postgres=# CREATE TEMP TABLE foo1 (serial_num int, name text, type text);
CREATE TABLE
postgres=# INSERT INTO foo1 VALUES (847001,'t15','GE1043');
INSERT 0 1
postgres=# INSERT INTO foo1 VALUES (847002,'t16','GE1043');
INSERT 0 1
postgres=# INSERT INTO foo1 VALUES (847003,'sub-alpha','GESS90');
INSERT 0 1
postgres=# SELECT json_arrayagg(type) from foo1;
ERROR:  function json_arrayagg(text) does not exist
LINE 1: SELECT json_arrayagg(type) from foo1;
               ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
postgres=

postgres=# select serial_num,JSON_OBJECTAGG(name,type) from foo1 group by serial_num;
ERROR:  function json_objectagg(text, text) does not exist
LINE 1: select serial_num,JSON_OBJECTAGG(name,type) from foo1 group ...
                          ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
postgres=

MogDB 排序算法并不比PG主流版本差

另外我在看PG16的new feature时发现提到在优化器方面又有一些改进,其中一点就是对于增量排序(Allow incremental sorts in more cases, including DISTINCT (David Rowley)。

这里我想说的是,MogDB在这方面实际上也做了一些努力,在MogDB 3.1版本之前其实还是比较慢的。不相信? 好吧,给你看看同为openGauss系的友商数据库性能。

orcl=# \copy mogdb_incresort_1 from '/tmp/MogDB_incresort_1.dat';
Time: 45158.913 ms
orcl=# select count(1) from mogdb_incresort_1;
  count   
----------
 10000000
(1 row)

Time: 3986.539 ms
orcl=#  select players.pname,
orcl-#      random() as lottery_number
orcl-#  from (
orcl(#          select distinct pname
orcl(#          from MogDB_incresort_1
orcl(#          group by pname
orcl(#          order by pname
orcl(#      ) as players
orcl-#  order by players.pname,
orcl-#      lottery_number
orcl-#  limit 20;
      pname       |  lottery_number   
------------------+-------------------
 player# 1        |  .693211137317121
 player# 10       |  .373950335662812
 player# 100      |  .748802043031901
 player# 1000     |  .868999985512346
 player# 10000    |  .708094645757228
 player# 100000   |  .146068200934678
 player# 1000000  |  .400482173077762
 player# 10000000 | .0748530034907162
 player# 1000001  |  .951222819741815
 player# 1000002  | .0985643910244107
 player# 1000003  |  .673836125060916
 player# 1000004  |  .493436659686267
 player# 1000005  |  .744129443541169
 player# 1000006  |   .45777113456279
 player# 1000007  |   .90621894877404
 player# 1000008  |  .818961981683969
 player# 1000009  |   .91224535740912
 player# 100001   |  .955949443858117
 player# 1000010  |  .175989827606827
 player# 1000011  | .0911367381922901
(20 rows)

Time: 33222.676 ms
orcl=# explain analyze
orcl-#  select players.pname,
orcl-#      random() as lottery_number
orcl-#  from (
orcl(#          select distinct pname
orcl(#          from MogDB_incresort_1
orcl(#          group by pname
orcl(#          order by pname
orcl(#      ) as players
orcl-#  order by players.pname,
orcl-#      lottery_number
orcl-#  limit 20;
                                                                              QUERY PLAN                                                                               
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=5984227.96..5984228.01 rows=20 width=128) (actual time=37477.723..37477.728 rows=20 loops=1)
   ->  Sort  (cost=5984227.96..6009228.03 rows=10000029 width=128) (actual time=37477.718..37477.719 rows=20 loops=1)
         Sort Key: players.pname, (random())
         Sort Method: top-N heapsort  Memory: 30kB
         ->  Subquery Scan on players  (cost=5518130.20..5718130.78 rows=10000029 width=128) (actual time=17705.988..34580.240 rows=10000000 loops=1)
               ->  Unique  (cost=5518130.20..5593130.42 rows=10000029 width=128) (actual time=17705.951..26398.773 rows=10000000 loops=1)
                     ->  Group  (cost=5518130.20..5568130.35 rows=10000029 width=128) (actual time=17705.947..23714.165 rows=10000000 loops=1)
                           Group By Key: mogdb_incresort_1.pname
                           ->  Sort  (cost=5518130.20..5543130.28 rows=10000029 width=128) (actual time=17705.940..20369.481 rows=10000000 loops=1)
                                 Sort Key: mogdb_incresort_1.pname
                                 Sort Method: external merge  Disk: 1350368kB
                                 ->  Seq Scan on mogdb_incresort_1  (cost=0.00..356411.29 rows=10000029 width=128) (actual time=0.020..2464.995 rows=10000000 loops=1)
 Total runtime: 37478.118 ms
(13 rows)

Time: 37480.533 ms

是的,你没有看错,这个简单的测试SQL 居然跑了30多秒。

那么我们来看在MogDB5.0.7版本中跑一下需要多久呢?

test=# \copy mogdb_incresort_1 from '/tmp/MogDB_incresort_1.dat';
test=# \timing on
test=# explain analyze
test-#  select players.pname,
test-#      random() as lottery_number
test-#  from (
test(#          select distinct pname
test(#          from MogDB_incresort_1
test(#          group by pname
test(#          order by pname
test(#      ) as players
test-#  order by players.pname,
test-#      lottery_number
test-#  limit 20;
                                                                             QUERY PLAN                                                                              
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=2174587.26..2174588.44 rows=20 width=64) (actual time=5315.519..5315.524 rows=20 loops=1)
   ->  Incremental Sort  (cost=2174587.26..2763354.30 rows=9999951 width=64) (actual time=5315.517..5315.518 rows=20 loops=1)
         Sort Key: players.pname, (random())
         Presorted Key: players.pname
         Full-sort Groups: 1  Sort Method: quicksort  Average Memory: 28kB Peak Memory: 28kB
         ->  Subquery Scan on players  (cost=2172256.79..2372255.81 rows=9999951 width=64) (actual time=5315.453..5315.487 rows=21 loops=1)
               ->  Unique  (cost=2172256.79..2247256.43 rows=9999951 width=64) (actual time=5315.433..5315.452 rows=21 loops=1)
                     ->  Group  (cost=2172256.79..2222256.55 rows=9999951 width=64) (actual time=5315.425..5315.442 rows=21 loops=1)
                           Group By Key: mogdb_incresort_1.pname
                           ->  Sort  (cost=2172256.79..2197256.67 rows=9999951 width=64) (actual time=5315.420..5315.425 rows=21 loops=1)
                                 Sort Key: mogdb_incresort_1.pname
                                 Sort Method: external merge  Disk: 665520kB
                                 ->  Seq Scan on mogdb_incresort_1  (cost=0.00..223456.51 rows=9999951 width=64) (actual time=0.012..1828.749 rows=10000000 loops=1)
 Total runtime: 5449.456 ms
(14 rows)

Time: 5457.669 ms
test=#  select players.pname,
test-#      random() as lottery_number
test-#  from (
test(#          select distinct pname
test(#          from MogDB_incresort_1
test(#          group by pname
test(#          order by pname
test(#      ) as players
test-#  order by players.pname,
test-#      lottery_number
test-#  limit 20;
      pname       |   lottery_number   
------------------+--------------------
 player# 1        |  0.579584513325244
 player# 10       |  0.836566388607025
 player# 100      |  0.843441488686949
 player# 1000     |  0.718995271716267
 player# 10000    |  0.892783336341381
 player# 100000   |   0.10398242296651
 player# 1000000  |  0.308310507796705
 player# 10000000 | 0.0168832587078214
 player# 1000001  |  0.446922336239368
 player# 1000002  | 0.0639159493148327
 player# 1000003  |  0.313714498188347
 player# 1000004  |  0.516515084076673
 player# 1000005  |  0.702487968374044
 player# 1000006  |  0.277854182291776
 player# 1000007  |  0.934525999706239
 player# 1000008  |   0.72923140367493
 player# 1000009  |  0.321010332554579
 player# 100001   |  0.651651729829609
 player# 1000010  |  0.506305878516287
 player# 1000011  |   0.46931520383805
(20 rows)

Time: 4521.001 ms
test=#   

大家可以看到,其实也就不到5s的样子的。还是比较快的。

最后我们看下相同的SQL在PG13中运行效率如何。

postgres=#  create table MogDB_incresort_1 (id int, pname name, match text);
CREATE TABLE
postgres=#  create index on MogDB_incresort_1(id);
CREATE INDEX
postgres=# insert into MogDB_incresort_1
postgres-#  values (
postgres(#          generate_series(1, 10000000),
postgres(#          'player# ' || generate_series(1, 10000000),
postgres(#          'match# ' || generate_series(1, 11)
postgres(#      );
 INSERT 0 10000000
postgres=#  
postgres=
postgres=#  select count(1) from MogDB_incresort_1;
  count   
----------
 10000000
(1 row)

postgres=#  vacuum analyze MogDB_incresort_1;
VACUUM
postgres=# \timing on
Timing is on.
postgres=#   set max_parallel_workers_per_gather = 0;
SET
Time: 0.250 ms
postgres=#  select players.pname,
postgres-#      random() as lottery_number
postgres-#  from (
postgres(#          select distinct pname
postgres(#          from MogDB_incresort_1
postgres(#          group by pname
postgres(#          order by pname
postgres(#      ) as players
postgres-#  order by players.pname,
postgres-#      lottery_number
postgres-#  limit 20;
      pname       |   lottery_number    
------------------+---------------------
 player# 1        |  0.0447521551191592
 player# 10       |   0.408278868270898
 player# 100      |  0.7921926875019913
 player# 1000     | 0.11271848207791635
 player# 10000    |  0.2647472418342467
 player# 100000   |  0.1412932234901234
 player# 1000000  |  0.4266691727193681
 player# 10000000 | 0.46474439957439273
 player# 1000001  | 0.23216838816411567
 player# 1000002  |  0.1229366164369452
 player# 1000003  |  0.3386561272461357
 player# 1000004  |  0.4146373941657302
 player# 1000005  | 0.28414336215408653
 player# 1000006  |  0.3686260468699629
 player# 1000007  |  0.1296536218416513
 player# 1000008  | 0.22829014039084683
 player# 1000009  | 0.15364363544027881
 player# 100001   | 0.08520628747068315
 player# 1000010  |   0.697556601432435
 player# 1000011  |  0.7879138632733813
(20 rows)

Time: 3637.823 ms (00:03.638)
postgres=# explain analyze
postgres-#  select players.pname,
postgres-#      random() as lottery_number
postgres-#  from (
postgres(#          select distinct pname
postgres(#          from MogDB_incresort_1
postgres(#          group by pname
postgres(#          order by pname
postgres(#      ) as players
postgres-#  order by players.pname,
postgres-#      lottery_number
postgres-#  limit 20;
                                                                              QUERY PLAN                                                                              
----------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=1765110.33..1765111.80 rows=20 width=72) (actual time=3759.205..3759.210 rows=20 loops=1)
   ->  Incremental Sort  (cost=1765110.33..2498764.46 rows=10000017 width=72) (actual time=3759.203..3759.206 rows=20 loops=1)
         Sort Key: players.pname, (random())
         Presorted Key: players.pname
         Full-sort Groups: 1  Sort Method: quicksort  Average Memory: 27kB  Peak Memory: 27kB
         ->  Subquery Scan on players  (cost=1762114.60..1962114.94 rows=10000017 width=72) (actual time=3759.173..3759.192 rows=21 loops=1)
               ->  Unique  (cost=1762114.60..1837114.73 rows=10000017 width=64) (actual time=3759.168..3759.184 rows=21 loops=1)
                     ->  Group  (cost=1762114.60..1812114.69 rows=10000017 width=64) (actual time=3759.167..3759.178 rows=21 loops=1)
                           Group Key: mogdb_incresort_1.pname
                           ->  Sort  (cost=1762114.60..1787114.64 rows=10000017 width=64) (actual time=3759.164..3759.169 rows=21 loops=1)
                                 Sort Key: mogdb_incresort_1.pname
                                 Sort Method: external merge  Disk: 724152kB
                                 ->  Seq Scan on mogdb_incresort_1  (cost=0.00..223457.17 rows=10000017 width=64) (actual time=0.010..1315.358 rows=10000000 loops=1)
 Planning Time: 0.095 ms
 Execution Time: 3897.663 ms
(15 rows)

Time: 3898.239 ms (00:03.898)
postgres=

我们可以看到实际上PG13版本也差不多需要4s左右。

而且细心一点的朋友还可以发现,其中的sort method部分,MogDB似乎看起来比pg13还要好一些。

后面我发现去年研发团队有同事分享过MogDB排序方面的知识,看pdf材料内容,其实应该是借鉴了PostgreSQL15的相关算法。

alt

好了,言归正传!

基于如上三点!所以你们还会觉得MogDB比PG差几代么?

本文由 mdnice 多平台发布

相关文章:

openGauss真的比PostgreSQL差了10年?

前不久写了MogDB针对PostgreSQL的兼容性文章,我在文中提到针对PostgreSQL而言,MogDB兼容性还是不错的,其中也给出了其中一个能源客户之前POC的迁移报告数据。 But很快我发现总有人回留言喷我,而且我发现每次喷的这帮人是根本不看文…...

【国产开源可视化引擎Meta2d.js】快速上手

提示 初始化引擎后,会生成一个 meta2d 全局对象,可直接使用。 调用meta2d前,需要确保meta2d所在的父容器element元素位置大小已经渲染完成。如果样式或css(特别是css动画)没有初始化完成,可能会报错&…...

c#与倍福Plc通信

bcdedit /set hypervisorlaunchtype off...

【OceanBase诊断调优】—— 如何通过trace_id找到对应的执行节点IP

1. 前言 OceanBase作为分布式数据库,查问题找对节点很关键。好在OceanBase执行的每一条SQL都能通过trace_id来关联起来,知道trace_id怎么知道是在哪个节点发起的呢,请看本文。 2. trace_id生成规则 ob内部trace_id的生成函数如下&#xff0…...

鸿蒙开发Ability Kit(程序访问控制):【使用粘贴控件】

使用粘贴控件 粘贴控件是一种特殊的系统安全控件,它允许应用在用户的授权下无提示地读取剪贴板数据。 在应用集成粘贴控件后,用户点击该控件,应用读取剪贴板数据时不会弹窗提示。可以用于任何应用需要读取剪贴板的场景,避免弹窗…...

PL/SQL入门到实践

一、什么是PL/SQL PL/SQL是Procedural Language/Structured Query Language的缩写。PL/SQL是一种过程化编程语言,运行于服务器端的编程语言。PL/SQL是对SQL语言的扩展。PL/SQL结合了SQL语句和过程性编程语言的特性,可以用于编写存储过程、触发器、函数等…...

双非本 985 硕,我马上要入职上海AI实验室大模型算法岗

暑期实习基本结束了,校招即将开启。 不同以往的是,当前职场环境已不再是那个双向奔赴时代了。求职者在变多,HC 在变少,岗位要求还更高了。 最近,我们又陆续整理了很多大厂的面试题,帮助一些球友解惑答疑&…...

C盘清理和管理

本篇是C盘一些常用的管理方法,以及定期清理C盘的方法,大部分情况下都能避免C盘爆红。 C盘清理和管理 C盘存储管理查看存储情况清理存储存储感知清理临时文件清理不需要的 迁移存储 磁盘清理桌面存储管理应用存储管理浏览器微信 工具清理 C盘存储管理 查…...

晚上睡觉要不要关路由器?一语中的

前言 前几天小白去了一个朋友家,有朋友说:路由器不关机的话会影响睡眠吗? 这个影响睡眠嘛,确实是会的。毕竟一时冲浪一时爽,一直冲浪一直爽……刷剧刷抖音刷到根本停不下来,肯定影响睡眠。 所以晚上睡觉要…...

ardupilot开发 --- 坐标变换 篇

Good Morning, and in case I dont see you, good afternoon, good evening, and good night! 0. 一些概念1. 坐标系的旋转1.1 轴角法1.2 四元素1.3 基于欧拉角的旋转矩阵1.3.1 单轴旋转矩阵1.3.2 多轴旋转矩阵1.3.3 其他 2. 齐次变换矩阵3. visp实践 0. 一些概念 相关概念&am…...

git clone 别人项目后正确的修改和同步操作

简介 git clone主要是克隆别人的开源项目。但更高端的操作是实现本地修改的同时,能同步别人的在线修改,并且不相互干扰: 克隆原始项目:从远程仓库克隆项目到本地。添加上游仓库:将原始项目的远程仓库添加为上游仓库。…...

JAVA连接FastGPT实现流式请求SSE效果

FastGPT 是一个基于 LLM 大语言模型的知识库问答系统,提供开箱即用的数据处理、模型调用等能力。同时可以通过 Flow 可视化进行工作流编排,从而实现复杂的问答场景! 一、先看效果 真正实流式请求,SSE效果,SSE解释&am…...

二分查找1

1. 二分查找(704) 题目描述: 算法原理: 暴力解法就是遍历数组来找到相应的元素,使用二分查找的解法就是每次在数组中选定一个元素来将数组划分为两部分,然后因为数组有序,所以通过大小关系舍弃…...

什么美业门店管理系统好用?2024美业收银系统软件排名分享

美业SAAS系统在美容、美发、美甲等行业中十分重要,这种系统为美业提供了一种数字化解决方案,帮助企业更高效地管理业务和客户关系。 美业门店管理系统通常提供预约管理、客户管理、库存管理、报表生成等一系列功能,以满足美容院、美发沙龙等…...

【文件上传】

文件上传漏洞 FileUpload 0x01 定义 服务端未对客户端上传文件进行严格的 验证和过滤造成可上传任意文件情况;0x02 攻击满足条件: 1. 上传文件能够被Web容器解释执行   2. 找到文件位置   3.上传文件未被改变内容。(躲避安全检查&#…...

Golang 单引号、双引号和反引号的概念、用法以及区别

在 Golang(Go 语言)中,单引号 ()、双引号 (") 和反引号 () 用于不同类型的字符串和字符表示。以下是它们的概念、用法和区别: 1. 单引号 () 概念 单引号用于表示 字符(rune 类型)。一个字符表示一个…...

linux和mysql基础指令

Linux中nano和vim读可以打开记事文件。 ifdown ens33 ifup ens33 关闭,开启网络 rm -r lesson1 gcc -o code1 code1.c 编译c语言代码 ./code1 执行c语言代码 rm -r dir 删除文件夹 mysql> show databases-> ^C mysql> show databases; -------…...

JDK 为什么需要配置环境变量

前言 首先,我们要知道 Java 程序的执行过程。首先将 xxx.java 文件(使用 javac 编译指令)编译成 xxx.class 文件(字节码文件),再将字节码文件(使用 java 执行指令)解释成电脑所能认识…...

ViewBinding的使用(因为kotlin-android-extensions插件的淘汰)

书籍: 《第一行代码 Android》第三版 开发环境: Android Studio Jellyfish | 2023.3.1 问题: 3.2.4在Activity中使用Toast章节中使用到了kotlin-android-extensions插件,但是该插件已经淘汰,根据网上了解,目前使用了新的技术VewBinding替…...

IOS Swift 从入门到精通:ios 连接数据库 安装 Firebase 和 Firestore

创建 Firebase 项目 导航到Firebase 控制台并创建一个新项目。为项目指定任意名称。 在这里插入图片描述 下一步,启用 Google Analytics,因为我们稍后会用到它来发送推送通知。 在这里插入图片描述 在下一个屏幕上,选择您的 Google Analytics 帐户(如果已创建)。如果没…...

QT4-QT5(6)-const char* QString 乱码转换

我简单粗暴的给出个结论: QString GBK编码正常,可以转UTF-8编码,但会有少量乱码。 const char* 编码就不要转编码,转哪个都是乱码。 UTF-8.cpp 下 1.QString GBK->UTF-8 2.const char * GBK->UTF-8 const char *…...

报错:RuntimeError_ cuDNN error_ CUDNN_STATUS_EXECUTION_FAILED

原因:pytorch与cuda版本不对 也有可能是内存空间不足,可以更改虚拟空间大小,参考:解决电脑内存不足问题:Win10虚拟内存设置指南...

黑马点评项目总结1-使用Session发送验证码和登录login和 使用Redis存储验证码和Redis的token登录

黑马先是总结了从session实现登录,然后是因为如果使用了集群方式的服务器的话,存在集群共享session互相拷贝效率低下的问题,接着引出了速度更快的内存型的kv数据库Redis, 使用Session发送验证码和登录login 举个例子&#xff1a…...

【大模型】Vllm基础学习

前言:vllm是一个大语言模型高速推理框架,旨在提高大模型的服务效率。优势是内存管理,实现的核心是pageattetion算法。仅在gpu上加速,不在cpu加速。 目录 1. PageAttention2. 实践2.1 安装2.2 离线推理2.3 适配OpenAI的api 1. Page…...

使用vue动态给同一个a标签添加内容 并给a标签设置hover,悬浮文字变色,结果鼠标悬浮有的字上面不变色

如果Vue的虚拟DOM更新机制导致样式更新不及时,你可以尝试以下几种方法来解决这个问题: 确保使用响应式数据: 确保你使用的数据是响应式的,并且任何对这些数据的更改都会触发视图的更新。在Vue中,你应该使用data对象中的…...

【ajax实战06】进行文章发布

本文章目标:收集文章内容,并提交服务器保存 一:基于form-serialize插件收集表单数据 form-serialize插件仅能收集到表单数据,除此之外的数据无法收集到 二:基于axios提交到服务器保存 三:调用alert警告…...

Codeforces Round 954 (Div. 3)(A~E)

目录 A. X Axis B. Matrix Stabilization C. Update Queries D. Mathematical Problem A. X Axis Problem - A - Codeforces 直接找到第二大的数&#xff0c;答案就是这个数与其他两个数的差值的和。 void solve() {vector<ll>a;for (int i 1; i < 3; i){int x;…...

基于Java微信小程序同城家政服务系统设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f;感兴趣的可以先收藏起来&#xff0c;还…...

[21] Opencv_CUDA应用之使用Haar级联的对象检测

Opencv_CUDA应用之使用Haar级联的对象检测 Haar级联使用矩形特征来检测对象,它使用不同大小的矩形来计算不同的线和边缘特征。矩形包含一些黑色和白色区域,如下图所示,它们在图像的不同位置居中 类Haar特征检测算法的思想是计算矩形内白色像素和黑色像素之间的差异这个方法的…...

CXL:拯救NVMe SSD缓存不足设计难题-2

LMB提出了基于CXL协议的内存扩展框架和内核模块。该方案利用CXL内存扩展器作为物理DRAM源&#xff0c;旨在提供一个统一的内存分配接口&#xff0c;使PCIe和CXL设备都能方便地访问扩展的内存资源。通过这个接口&#xff0c;NVMe驱动和CUDA的统一内存内核驱动可以直接高效地访问…...

Opencv学习项目6——pyzbar

在之前我们学习了解码图片中的二维码&#xff0c;这次我们开启摄像头来解码视频中二维码 开启摄像头 # 打开摄像头 cap cv2.VideoCapture(0) cap.set(3, 640) # 设置摄像头画面宽度 cap.set(4, 480) # 设置摄像头画面高度 我使用的是笔记本上的摄像头来进行的&#xff0c;…...

Switch 刷安卓11 (LineageOS 18.1) 大气层双系统图文教程

很多朋友手上已经拥有了完成硬破的 Switch &#xff0c;但又不甘心仅仅使用 Switch 本身的地平线系统&#xff0c;Switch 刷安卓 (Android 11) 会是一个好的选择&#xff0c;虽然 Switch 的 CPU 性能拉跨&#xff0c;但和桌面平台同一设计思路的TegraX1 GPU 可谓是先于时代&…...

Spring Boot与Spring Batch的深度集成

Spring Boot与Spring Batch的深度集成 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天我们将深入探讨在Spring Boot应用中如何实现与Spring Batch的深度集成…...

RTSP协议在视频监控系统中的典型应用、以及视频监控设备的rtsp地址格式介绍

目录 一、协议概述 1、定义 2、提交者 3、位置 二、主要特点 1、实时性 2、可扩展性 3、控制功能 4、回放支持 5、网络适应性 三、RTSP的工作原理 1、会话准备 2、会话建立 3、媒体流控制 4、会话终止 5、媒体数据传输 四、协议功能 1、双向性 2、带外协议 …...

Kotlin基础——异步和并发

同步和异步 同步指的是一种行为&#xff1a;当执行IO操作的时候&#xff0c;在代码层面上我们需要主动去等待结果&#xff0c;直到结果返回阻塞指的是一种状态&#xff1a;当执行IO操作的时候&#xff0c;线程处于挂起状态&#xff0c;就是该线程没有执行了 故同步不是阻塞&a…...

消防认证-防火卷帘

一、消防认证 消防认证是指消防产品符合国家相关技术要求和标准&#xff0c;且通过了国家认证认可监督管理委员会审批&#xff0c;获得消防认证资质的认证机构颁发的证书&#xff0c;消防产品具有完好的防火功能&#xff0c;是住房和城乡建设领域验收的重要指标。 二、认证依据…...

SpringBoot3.3集成knif4j-swagger文档方式和使用案例

springboot3 集成 knif4j &#xff1a; 访问地址&#xff1a; swagger 接口文档默认地址&#xff1a;http://localhost:8080/swagger-ui.html# Knife4j 接口文档默认地址&#xff1a;http://127.0.0.1:8080/doc.html Maven: <dependency><groupId>com.github.x…...

老年服务与管理实训室:制定教学模式

随着我国人口老龄化程度的加深,如何为老年人提供优质的养老服务成为社会关注的重点。作为培养老年服务人才的重要阵地,老年服务与管理实训室应制定科学合理的教学模式,满足行业发展需求,培养出高素质的老年服务专业人才。本文针对老年服务与管理实训室的教学模式展开探讨,提出相…...

4、DDD、中台和微服务的关系

DDD、中台和微服务的关系 1 DDD和中台的本质 领域驱动设计&#xff08;DDD&#xff09;和中台在企业架构中有着密切的关系。DDD的本质在于通过对业务领域的深入分析和建模&#xff0c;构建高内聚、低耦合的系统。而中台则是对企业核心业务能力的抽象和封装&#xff0c;以实现…...

【ACM出版,马来西亚-吉隆坡举行】第四届互联网技术与教育信息化国际会议 (ITEI 2024)

作为全球科技创新大趋势的引领者&#xff0c;中国不断营造更加开放的科技创新环境&#xff0c;不断提升学术合作的深度和广度&#xff0c;构建惠及各方的创新共同体。这是对全球化的新贡献&#xff0c;是构建人类命运共同体的新贡献。 第四届互联网技术与教育信息化国际学术会议…...

走进IT的世界

引言 随着高考的结束&#xff0c;对于即将踏入IT&#xff08;信息技术&#xff09;领域的新生而言&#xff0c;这个假期不仅是放松身心的时间&#xff0c;更是提前规划、深化专业知识、为大学生活奠定坚实基础的宝贵机会。以下是一份详尽的高考假期预习与规划指南&#xff0c;…...

Linux 时区文件编译器 zic【man 8 zic】

1. NAME&#xff08;名&#xff09; zic - 时区编译器 2. SYNOPSIS&#xff08;概要&#xff09; zic [-v] [-d directory] [-l localtime] [-p posixrules] [-L leapsecondfilename] [-s] [-y command] [filename ...]3. DESCRIPTION&#xff08;函数描述&#xff09; zic…...

Springboot下使用Redis管道(pipeline)进行批量操作

之前有业务场景需要批量插入数据到Redis中&#xff0c;做的过程中也有一些感悟&#xff0c;因此记录下来&#xff0c;以防忘记。下面的内容会涉及到 分别使用for、管道处理批量操作&#xff0c;比较其所花费时间。 分别使用RedisCallback、SessionCallback进行Redis pipeline …...

Vue技巧大揭秘:自定义指令的力量与应用

引言 自定义指令就像是给予开发者的一把魔法钥匙&#xff0c;它能够打开DOM操作的新世界&#xff0c;按我的理解就是把对DOM操作的逻辑进行封装 全局注册与局部注册 全局注册 定义&#xff1a; 全局注册意味着自定义指令在Vue实例创建之前通过Vue.directive()方法注册&…...

HR人才测评,如何考察想象力?

什么是想象力&#xff1f; 想象力是指&#xff0c;人们通过在已有物质的基础上&#xff0c;通过大脑想象、加工、创造出新事物的能力&#xff0c;举一个非常简单的例子&#xff0c;在提到鸟这种生活的时候&#xff0c;大家会联想到各种各样不同鸟的品种。 在企业招聘中常常应…...

Git命令远程分支的合并和本地分支的同步

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…...

墨烯的C语言技术栈-C语言基础-003

三.数据类型 1.char // 字符数据型 2.short // 短整型 3.int // 整型 4.long // 长整型 5.long long // 更长的整型 6.float // 单精度浮点数 7.double // 双精度浮点数 为什么写代码? 为了解决生活中的问题 购物,点餐,看电影 为什么有这么多类型呢? 因为说的话都是字符型…...

RpcRrovider分发rpc服务(OnMessage和Closure回调)

目录 1.完善rpcprovider.cc的OnConnection 2.完善rpcprovider.cc的OnMessage 3.完整rpcprovider.h 4.完整rpcprovider.cc 这篇文章主要完成&#xff0c;protobuf实现的数据序列化和反序列化。 1.完善rpcprovider.cc的OnConnection rpc的请求是短连接的&#xff0c;请求一次…...

分解+降维+预测!多重创新!直接写核心!EMD-KPCA-Transformer多变量时间序列光伏功率预测

分解降维预测&#xff01;多重创新&#xff01;直接写核心&#xff01;EMD-KPCA-Transformer多变量时间序列光伏功率预测 目录 分解降维预测&#xff01;多重创新&#xff01;直接写核心&#xff01;EMD-KPCA-Transformer多变量时间序列光伏功率预测效果一览基本介绍程序设计参…...

【Python】MacBook M系列芯片Anaconda下载Pytorch,并开发一个简单的数字识别代码(附带踩坑记录)

文章目录 配置镜像源下载Pytorch验证使用Pytorch进行数字识别 配置镜像源 Anaconda下载完毕之后&#xff0c;有两种方式下载pytorch&#xff0c;一种是用页面可视化的方式去下载&#xff0c;另一种方式就是直接用命令行工具去下载。 但是由于默认的Anaconda走的是外网&#x…...

轻松设置:服务器域名配置全攻略

目录 前置条件 在阅读本篇内容之前&#xff0c;请先确保以下物料已准备好&#xff1a; 一台公网服务器&#xff0c;服务正常运行申请完成的域名&#xff0c;在对应域名服务商后台正常DNS解析域名备案完成可选条件&#xff1a;有https访问请求时&#xff0c;需要申请SSL证书 …...

RabbitMQ入门教程(精细版二带图)

目录 六 RabbitMQ工作模式 6.1Hello World简单模式 6.1.1 什么是简单模式 6.1.2 RabbitMQ管理界面操作 6.1.3 生产者代码 6.1.4 消费者代码 6.2 Work queues工作队列模式 6.2.1 什么是工作队列模式 6.2.2 RabbitMQ管理界面操作 6.2.3 生产者代码 6.2.4 消费者代码 …...

字节跳动 AML 前端 一面

时长55mins 1. 自我介绍 1. 怎么接触的前端&#xff1f;学了多久&#xff1f; 1. 问项目 1. 为什么要做组件库&#xff1f; 1. 问到我的组件库和AntD之类的有什么区别&#xff0c;我说区别可能就是我的功能更少&#xff1f;hhhh 1. 设计一个组件的思路&#x…...

python 身份证工具

介绍&#xff1a; 可以解析身份证&#xff0c;获取身份证的省&#xff0c;市&#xff0c;区信息&#xff0c;年龄&#xff0c;性别&#xff0c;生日信息 import re from datetime import datetime import jsonclass IDCardParserUtil:def __init__(self):pass# 身份证号码前6位…...

Elasticsearch集群部署(上)

目录 前言 一. 环境准备 二. 实施部署 三. 安装配置head监控插件 &#xff08;只在第一台es部署&#xff09; 四. Kibana部署&#xff08;当前还是在第一台es部署&#xff09; 五. 安装配置Nginx反向代理 六. Logstash部署与测试 下篇&#xff1a;Elasticsearch集群部…...

EXPLAIN--SQL执行计划各个参数含义

目录 一、简介 二、详细介绍 三、意义 一、简介 EXPLAIN是SQL语句中用于分析和显示执行计划的命令&#xff0c;主要用于帮助理解查询是如何被数据库优化器处理的。在不同的数据库系统中&#xff08;如MySQL、PostgreSQL、SQLite等&#xff09;&#xff0c;EXPLAIN的具体语法…...

冰箱也安排上了?第二代AIONV内饰发布,会成为爆款么

作为埃安品牌在SUV市场的顶梁柱车型之一,AION V凭借凭借扎实的三电技术和前卫的外观设计、科技感十足的内饰等,获得了消费者的广泛认可。不过面对激烈的纯电动车市场,现款AION V的市场竞争力也在逐渐减退。在这样的局面下,埃安也带来了全新换代的第二代AION V。新车在北京车…...

7.2秒!大众途昂尊荣四驱高速极限测试

大众途昂高速极限测试。你想知道大众途昂尊荣四驱在高速上的极限速度吗?今天来进行一场高速极限测试。动力方面搭载一台2.5TV6发动机,最大马力为299匹,最大扭矩为500牛米,官方百公里加速时间为7.2秒。大众途昂尊荣四驱是一款以性能出色、操控稳定而著称的SUV车型,无论是越…...

数据库技术基础

数据库技术基础 导航 文章目录 数据库技术基础导航一、基础概念数据库系统数据库管理系统DBMS分类数据库技术的发展数据库体系结构 二、数据模型数据模型基本概念 三、数据库的控制功能事务概述SOL中事务定义语句日志文件故障种类两个操作Undo/Redo事务故障的恢复系统故障的恢…...

【Sql Server】随机查询一条表记录,并重重温回顾下自定义函数的封装和使用

大家好&#xff0c;我是全栈小5&#xff0c;欢迎来到《小5讲堂》。 这是《Sql Server》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 前言随机查询语…...

对北京新发地当时菜品三十天内价格分布式爬取(1)---(获取当时菜品数据并构建请求数据推入redis)

本次项目网页url 北京新发地: http://www.xinfadi.com.cn/priceDetail.html 我们首先创建一个爬虫用于收集url与请求的data然后b,c,d使用RedisCrawlSpider来对数据进行分布式爬取 在此篇中我们仅介绍爬虫a 一.获取当天所有菜品数据 这是一条请求的负载我们只需要对pubDateSta…...

linux input 驱动

使用文档 设备树修改 新增一个 LED 节点 arch/arm/boot/dts/arm/vexpress-v2p-ca9.dts my_pl_led {compatible = "arm, cortex-a9-led";status = "okay";};设备树编译 make dtbs日志 DTC arch/arm/boot/dts/arm/vexpress...