99国产精品欲av蜜臀,可以直接免费观看的AV网站,gogogo高清免费完整版,啊灬啊灬啊灬免费毛片

網易首頁 > 網易號 > 正文 申請入駐

pg_mooncake:PostgreSQL的高性能列存新貴

0
分享至

一、前言

在上一篇文章中,我們有講到pg_duckdb對于SELECT語句的一個較為詳細的處理流程,能大概了解到pg_duckdb是如何加速查詢效率的(甚至在某些場景之下,獲得上千倍的提升不在話下),同樣也知道了它的加速是有限制的,其限制的瓶頸點在于它需要將PostgreSQL中的行存儲的數據一行一行的轉換填充之duckdb的列存之中(實話實話,這成本過于高昂),所以當且僅當這個加載數據轉換的時間和原本查詢的時間越顯得不值一提的時候,實際加速的效果就越好。

依舊是在上篇文章中,有聊到pg_duckdb的技術路線是Custom Scan,但其實并不僅僅是Custom Scan,它也實現了TAM(Table Access Method),只不過限制僅支持臨時表,所以在當時我也沒有多少想講的意愿,而是留給今天的主角pg_mooncake。

pg_mooncake是在pg_duckdb上構建的,相對而言是青出于藍而勝于藍,因為它涵蓋了pg_duckdb,所以它的技術路線也包括了Custom Scan,不過它在TAM(Table Access Method)方面做的更好,它不再局限于臨時表的同時給PostgreSQL帶來了真正的列式存儲。

這里我稱呼它為PostgreSQL的列存新貴的原因在于:在它之前,其實就存在列式存儲插件,因為要想AP跑的好,列式存儲少不了,其實有了列存也還不夠,計算方面也得跟上。

所以在pg_mooncake的前面還有些"老前輩",比如說 hydradatabase(現在在整pg_duckdb的那位)的開源項目columnar,加速效果也有,但是效果不是那么理想。但是它也解決了不少問題,比方說是數據壓縮,因為列式存儲在壓縮上具有天然的優勢,可以做到較高的壓縮率,節省空間。

伴隨著時代的進步,duckdb的出現,從而出現了更加優秀的列式存儲插件pg_mooncake,還是非常值得高興的。

關于TAM(Table Access Method)相關資料請參考PostgreSQL的官方文檔https://www.postgresql.org/docs/16/sql-create-access-method.html。

二、Mooncake Labs團隊

在正式玩起來之前呢,我想先簡單介紹一下pg_mooncake的技術團隊,畢竟我和他們團隊的cc大佬還算是挺聊的來、也蠻有緣的(雖然我總是因為有事情要忙,以至于經常咕咕咕人家)。

pg_mooncake是由Mooncake Labs團隊打造的一個開源項目,而Mooncake Labs是坐落在美國舊金山的一支技術非常NB的團隊。

他們中大多數的成員都來自海外的一家名為SingleStore的公司,如果大家對這家公司有過了解的話,應該能大概知道這家公司在海外HTAP還是算挺有名氣的。因此Mooncake Labs團隊中的成員也積攢了大量關于這方面的經驗,這可能也是他們能把pg_mooncake優化到ClickBench前10的一個原因吧(雖然現在可能降了一點,但是無傷大雅)。


(這是之前的記錄圖片)

他們團隊也是正在招人(有挺多的方向,這里我只提一嘴數據庫內核方向),感興趣的同學可以去試試。

官網主頁:https://pgmooncake.com/

招聘信息:https://mooncakelabs.notion.site/build-the-mooncake-11cb7b68b5c1802a84a9e21649f49477

三、pg_mooncake

接下來進入正篇,讓我們走進pg_mooncake。

github項目地址:https://github.com/Mooncake-Labs/pg_mooncake

還是以源碼安裝為例,可參考https://github.com/Mooncake-Labs/pg_mooncake/blob/main/CONTRIBUTING.md

# contrib目錄
cd $PostgreSQL源碼目錄/contrib
# 拉取項目源碼
git clone https://github.com/Mooncake-Labs/pg_mooncake.git
# 進入代碼目錄
cd pg_mooncake/
# 拉取duckdb子項目
git submodule update --init --recursive
# 編譯debug版本或者release版本
make debug # make release
# 等待編譯完成即可 此處還有一個前提是安裝好Rust的cargo
make install 

和pg_duckdb不同的是在使用上pg_mooncake不需要設置shared_preload_libraries,直接連接數據庫,創建拓展即可。

CREATE EXTENSION pg_mooncake;

3.1、簡單羅列一下相關參數

和pg_duckdb相比,pg_mooncake的參數則是要少得多,很清爽(畢竟pg_duckdb要帶貨)。如果只是簡單體驗體驗的話,就默認設置什么都不動就可以了。這里簡單羅列一下相關參數信息:

name

short_desc

mooncake.allow_local_tables

Allow columnstore tables on local disk

mooncake.default_bucket

Default bucket for columnstore tables

mooncake.enable_local_cache

Enable local cache for columnstore tables

mooncake.enable_memory_metadata_cache

Enable memory cache for Parquet metadata

mooncake.maximum_memory

The maximum memory DuckDB can use (e.g., 1GB)

mooncake.maximum_threads

Maximum number of DuckDB threads per Postgres backend

上面我們有說過pg_mooncake是將pg_duckdb糅合在一起,那可能有的朋友就很好奇,可能會提出這樣子的疑問就是說那么pg_duckdb的參數在pg_mooncake中是否有效呢?

答案是無效的,讓我們簡單看一下pgmooncake.cpp中的_PG_init就一目了然了

void _PG_init() {
    MooncakeInitGUC();
    DuckdbInitHooks(); 
    DuckdbInitNode();
    pgduckdb::RegisterDuckdbXactCallback();
// 略過部分代碼
}

可以看到pg_mooncake在_PG_init時不初始化pg_duckdb的相關參數,所以pg_duckdb的相關參數自然就無效了。

同時我們注意到它調用了pg_duckdb的DuckdbInitHooks、DuckdbInitNode這兩個接口(內部實際會有些許改動),也就是說從代碼層面論證了我們在上一篇文章中講到的內容在pg_mooncake依舊有效。

所以實際上來說,什么都不需要設置,創建完拓展之后就可以愉快的玩耍了。

3.2、簡單使用

在最開始的時候,我們指出了pg_duckdb的性能瓶頸可能在于將PostgreSQL中存儲的行數據轉換成duckdb的列數據。并且pg_duckdb僅對SELECT語句進行了額外的處理,對于其他SQL語句而言,如INSERT、UPDATE、DETELE都是交由PostgreSQL處理。

可能是pg_mooncake看到了這些痛點,所以它將INSERT、UPDATE、DETELE等等都給支持了,并在執行這些相關語句的時候,創建對應的Parquet文件,并存儲相關數據。當訪問列存表時,對于數據加載那塊便僅需要訪問對應的Parquet文件即可,就這樣避免了pg_duckdb在加載數據時的需要付出的昂貴成本。

而且物理文件使用Parquet文件作為外部存儲,對于構建數據湖也很方便。

以官方的測試案例為例:

[postgres@halo-centos8 mooncake_local_tables]$ psql mooncake
psql (16.8)
Type "help" for help.

mooncake=# \dx
                    List of installed extensions
    Name     | Version |   Schema   |          Description          
-------------+---------+------------+-------------------------------
 pg_mooncake | 0.1.2   | public     | Columnstore Table in Postgres
 plpgsql     | 1.0     | pg_catalog | PL/pgSQL procedural language
(2 rows)

mooncake=# -- 創建列存表
mooncake=# CREATE TABLE user_activity(
mooncake(#   user_id BIGINT,
mooncake(#   activity_type TEXT,
mooncake(#   activity_timestamp TIMESTAMP,
mooncake(#   duration INT
mooncake(# ) USING columnstore;
CREATE TABLE
mooncake=# -- 通過explain來簡單判斷INSERT是否被支持
mooncake=# EXPLAIN VERBOSE INSERT INTO user_activity VALUES
mooncake-#   (1, 'login', '2024-01-01 08:00:00', 120),
mooncake-#   (2, 'page_view', '2024-01-01 08:05:00', 30),
mooncake-#   (3, 'logout', '2024-01-01 08:30:00', 60),
mooncake-#   (4, 'error', '2024-01-01 08:13:00', 60);
                             QUERY PLAN                             
--------------------------------------------------------------------
 Custom Scan (MooncakeDuckDBScan)  (cost=0.00..0.00 rows=0 width=0)
   Output: duckdb_scan.explain_key, duckdb_scan.explain_value
   DuckDB Execution Plan: 

 ┌───────────────────────────┐
 │     COLUMNSTORE_INSERT    │
 └─────────────┬─────────────┘
 ┌─────────────┴─────────────┐
 │      COLUMN_DATA_SCAN     │
 │    ────────────────────   │
 │          ~4 Rows          │
 └───────────────────────────┘


(14 rows)

mooncake=# -- 插入數據
mooncake=# INSERT INTO user_activity VALUES
mooncake-#   (1, 'login', '2024-01-01 08:00:00', 120),
mooncake-#   (2, 'page_view', '2024-01-01 08:05:00', 30),
mooncake-#   (3, 'logout', '2024-01-01 08:30:00', 60),
mooncake-#   (4, 'error', '2024-01-01 08:13:00', 60);
INSERT 0 4
mooncake=# -- 查詢數據
mooncake=# SELECT * from user_activity;
 user_id | activity_type | activity_timestamp  | duration 
---------+---------------+---------------------+----------
       1 | login         | 2024-01-01 08:00:00 |      120
       2 | page_view     | 2024-01-01 08:05:00 |       30
       3 | logout        | 2024-01-01 08:30:00 |       60
       4 | error         | 2024-01-01 08:13:00 |       60
(4 rows)

mooncake=# -- 查看列存表對應物理文件位置
mooncake=# SELECT * FROM mooncake.columnstore_tables;
  table_name   |                                  path                                  
---------------+------------------------------------------------------------------------
 user_activity | /data/16/mooncake_local_tables/mooncake_mooncake_user_activity_279647/
(1 row)

如果你按照我的操作來進行的話,這個數據目錄不一定和我這里一樣,這個目錄的命名規則為$PGDATA/mooncake_local_tables/mooncake_數據庫名_表名_表oid

string ColumnstoreMetadata::GetTablePath(Oid oid) {
    ::Relation table = table_open(oid, AccessShareLock);
    string path =
        StringUtil::Format("mooncake_%s_%s_%d/", get_database_name(MyDatabaseId), RelationGetRelationName(table), oid);
    table_close(table, AccessShareLock);
    if (mooncake_default_bucket != nullptr && mooncake_default_bucket[0] != '\0') {
        path = StringUtil::Format("%s/%s", mooncake_default_bucket, path);
    } else if (mooncake_allow_local_tables) {
        path = StringUtil::Format("%s/mooncake_local_tables/%s", DataDir, path);
    } else {
        elog(ERROR, "Columnstore tables on local disk are not allowed. Set mooncake.default_bucket to default "
                    "S3 bucket");
    }
    return path;
}

而對應的parquet文件的命名則是非常明顯的uuid風格

file_name = UUID::ToString(UUID::GenerateRandomUUID()) + ".parquet";

讓我們看一下

/data/16/mooncake_local_tables/mooncake_mooncake_user_activity_279647/

這個目錄存在哪些東西

[postgres@halo-centos8 mooncake_local_tables]$ tree /data/16/mooncake_local_tables/mooncake_mooncake_user_activity_279647/
/data/16/mooncake_local_tables/mooncake_mooncake_user_activity_279647/
├── 721e8499-b4c3-4a4a-a822-5af1fc45e237.parquet
└── _delta_log
    ├── 00000000000000000000.json
    └── 00000000000000000001.json

1 directory, 3 files
[postgres@halo-centos8 mooncake_local_tables]$ cat /data/16/mooncake_local_tables/mooncake_mooncake_user_activity_279647/_delta_log/00000000000000000001.json
{"add":{"path":"721e8499-b4c3-4a4a-a822-5af1fc45e237.parquet","partitionValues":{},"size":699,"modificationTime":0,"dataChange":true,"stats":null,"tags":null,"deletionVector":null,"baseRowId":null,"defaultRowCommitVersion":null,"clusteringProvider":null}}
{"commitInfo":{"timestamp":1740987491586,"operation":"WRITE","operationParameters":{"mode":"Append"},"clientVersion":"delta-rs.0.21.0"}}

這里我們想嘗試去讀一下721e8499-b4c3-4a4a-a822-5af1fc45e237.parquet,可以用mooncake.read_parquet也可以用duckdb,這里我還是用duckdb來讀取

[postgres@halo-centos8 ~]$ ./duckdb 
v1.1.3 19864453f7
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
D select * from read_parquet('/data/16/mooncake_local_tables/mooncake_mooncake_user_activity_279647/721e8499-b4c3-4a4a-a822-5af1fc45e237.parquet');
┌─────────┬───────────────┬─────────────────────┬──────────┐
│ user_id │ activity_type │ activity_timestamp  │ duration │
│  int64  │    varchar    │      timestamp      │  int32   │
├─────────┼───────────────┼─────────────────────┼──────────┤
│       1 │ login         │ 2024-01-01 08:00:00 │      120 │
│       2 │ page_view     │ 2024-01-01 08:05:00 │       30 │
│       3 │ logout        │ 2024-01-01 08:30:00 │       60 │
│       4 │ error         │ 2024-01-01 08:13:00 │       60 │
└─────────┴───────────────┴─────────────────────┴──────────┘

可以看到和在PostgreSQL中讀取到的數據是一致的。

_delta_log中的相關json文件,就是實際對應的事務日志。json文件和parquet文件并不總是線性增長的,如下所示:

[postgres@halo-centos8 ~]$ psql mooncake
psql (16.8)
Type "help" for help.

mooncake=# BEGIN; -- 開啟事務塊
BEGIN
mooncake=*# INSERT INTO user_activity VALUES (5, 'test', '2024-01-01 08:13:00', 60);
INSERT 0 1
mooncake=*# INSERT INTO user_activity VALUES (6, 'test', '2024-01-01 08:13:00', 60);
INSERT 0 1
mooncake=*# ROLLBACK; -- 回滾事務
ROLLBACK

讓我們再次查看一下

/data/16/mooncake_local_tables/mooncake_mooncake_user_activity_279647/

的目錄結構和json數據

[postgres@halo-centos8 ~]$ tree /data/16/mooncake_local_tables/mooncake_mooncake_user_activity_279647/
/data/16/mooncake_local_tables/mooncake_mooncake_user_activity_279647/
├── 721e8499-b4c3-4a4a-a822-5af1fc45e237.parquet
├── 81d8cb44-0136-4cf6-8188-7a673ad1da92.parquet
├── _delta_log
│   ├── 00000000000000000000.json
│   └── 00000000000000000001.json
└── f7afb9b9-a876-4905-9990-74177f65ee22.parquet

1 directory, 5 files
[postgres@halo-centos8 ~]$ cat /data/16/mooncake_local_tables/mooncake_mooncake_user_activity_279647/_delta_log/00000000000000000001.json
{"add":{"path":"721e8499-b4c3-4a4a-a822-5af1fc45e237.parquet","partitionValues":{},"size":699,"modificationTime":0,"dataChange":true,"stats":null,"tags":null,"deletionVector":null,"baseRowId":null,"defaultRowCommitVersion":null,"clusteringProvider":null}}
{"commitInfo":{"timestamp":1740987491586,"operation":"WRITE","operationParameters":{"mode":"Append"},"clientVersion":"delta-rs.0.21.0"}}

可以發現json文件沒有發生任何變化,但是新增了兩個parquet文件,我們再次使用duckdb讀取一下此目錄中的所有parquet

[postgres@halo-centos8 ~]$ ./duckdb
v1.1.3 19864453f7
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
D select * from read_parquet('/data/16/mooncake_local_tables/mooncake_mooncake_user_activity_279647/*');  -- * 代表所有的parquet
┌─────────┬───────────────┬─────────────────────┬──────────┐
│ user_id │ activity_type │ activity_timestamp  │ duration │
│  int64  │    varchar    │      timestamp      │  int32   │
├─────────┼───────────────┼─────────────────────┼──────────┤
│       1 │ login         │ 2024-01-01 08:00:00 │      120 │
│       2 │ page_view     │ 2024-01-01 08:05:00 │       30 │
│       3 │ logout        │ 2024-01-01 08:30:00 │       60 │
│       4 │ error         │ 2024-01-01 08:13:00 │       60 │
│       5 │ test          │ 2024-01-01 08:13:00 │       60 │
│       6 │ test          │ 2024-01-01 08:13:00 │       60 │
└─────────┴───────────────┴─────────────────────┴──────────┘

可以看到我們回滾的那兩個記錄能被查詢到,所以實際上那兩個parquet分別對應一條INSERT語句。

3.3、行列混存

也正是因為pg_mooncake實現了列式存儲,所以對于PostgreSQL而言,便出現了行列混存的情形。最簡單的場景便是構建一張堆表和一張列存表,那么這兩張表可以join嗎?

答案是可以的。如下所示:

[postgres@halo-centos8 ~]$ psql mooncake
psql (16.8)
Type "help" for help.

mooncake=# CREATE TABLE ta(user_id BIGINT); -- 簡單堆表
CREATE TABLE
mooncake=# INSERT INTO ta SELECT * FROM generate_series(1, 6); -- 生成六行數據
INSERT 0 6
mooncake=# SELECT * FROM ta Inner Join user_activity on ta.user_id = user_activity.user_id; -- 簡單測試查看結果 
 user_id | user_id | activity_type | activity_timestamp  | duration 
---------+---------+---------------+---------------------+----------
       1 |       1 | login         | 2024-01-01 08:00:00 |      120
       2 |       2 | page_view     | 2024-01-01 08:05:00 |       30
       3 |       3 | logout        | 2024-01-01 08:30:00 |       60
       4 |       4 | error         | 2024-01-01 08:13:00 |       60
(4 rows)

mooncake=# EXPLAIN VERBOSE SELECT * FROM ta Inner Join user_activity on ta.user_id = user_activity.user_id; -- 簡單測試查看執行計劃 
                             QUERY PLAN                             
--------------------------------------------------------------------
 Custom Scan (MooncakeDuckDBScan)  (cost=0.00..0.00 rows=0 width=0)
   Output: duckdb_scan.explain_key, duckdb_scan.explain_value
   DuckDB Execution Plan: 

 ┌───────────────────────────┐
 │         PROJECTION        │
 │    ────────────────────   │
 │          user_id          │
 │          user_id          │
 │       activity_type       │
 │     activity_timestamp    │
 │          duration         │
 │                           │
 │         ~2260 Rows        │
 └─────────────┬─────────────┘
 ┌─────────────┴─────────────┐
 │         HASH_JOIN         │
 │    ────────────────────   │
 │      Join Type: INNER     │
 │                           │
 │        Conditions:        ├──────────────┐
 │     user_id = user_id     │              │
 │                           │              │
 │         ~2260 Rows        │              │
 └─────────────┬─────────────┘              │
 ┌─────────────┴─────────────┐┌─────────────┴─────────────┐
 │     POSTGRES_SEQ_SCAN     ││     COLUMNSTORE_SCAN      │
 │    ────────────────────   ││    ────────────────────   │
 │         Function:         ││         Function:         │
 │     POSTGRES_SEQ_SCAN     ││      COLUMNSTORE_SCAN     │
 │                           ││                           │
 │    Projections: user_id   ││        Projections:       │
 │                           ││          user_id          │
 │                           ││       activity_type       │
 │                           ││     activity_timestamp    │
 │                           ││          duration         │
 │                           ││                           │
 │         ~2260 Rows        ││          ~4 Rows          │
 └───────────────────────────┘└───────────────────────────┘


(41 rows)

所以顯而易見的是,pg_mooncake將數據都加載到了duckdb中,然后去執行了。

對于堆表而言,若當前SQL查詢存在列存表,會走原本pg_duckdb的邏輯,會將元組數據轉換成duckdb的列數據,對應POSTGRES_SEQ_SCAN。(如果當前查詢并不包含列存表,則走的PostgreSQL的默認邏輯)對于列存表而言,走的則是pg_mooncake自己提供的COLUMNSTORE_SCAN,實際上就是parquet_scan。

TableFunction ColumnstoreTable::GetScanFunction(ClientContext &context, unique_ptr &bind_data)  {
    auto file_names = metadata->DataFilesSearch(oid, &context, &path, &columns);
    auto file_paths = GetFilePaths(path, file_names);
    if (file_paths.empty()) {
        return TableFunction("columnstore_scan", {} /*arguments*/, EmptyColumnstoreScan);
    }

    TableFunction columnstore_scan = GetParquetScan(context);  -- 注意此處
    columnstore_scan.name = "columnstore_scan";
    columnstore_scan.init_global = ColumnstoreScanInitGlobal;
    columnstore_scan.statistics = nullptr;
    columnstore_scan.get_multi_file_reader = ColumnstoreScanMultiFileReader::Create;
// 省略代碼...
}

//對應此處
TableFunction GetParquetScan(ClientContext &context) {
    return ExtensionUtil::GetTableFunction(*context.db, "parquet_scan")  -- 實際是parquet_scan
        .functions.GetFunctionByArguments(context, {LogicalType::LIST(LogicalType::VARCHAR)});
}

所以pg_mooncake還是設計的蠻巧妙的。歡迎感興趣的同學可以去點點Star,提提PR。

3.4、不足之處?

這其實倒沒啥好說的了,我能注意到的必然也逃不過pg_mooncake的大佬的法眼。一般的都被記錄到Issues中了。

比方說資源管理之類的,如drop table之后,對應的物理目錄及文件未被及時清除之類的;

比如說性能優化之類的,如https://github.com/Mooncake-Labs/pg_mooncake/issues/82。

聽說cc他們規劃后續會將pg_mooncake做成一個基于PostgreSQL的HTAP數據庫,讓人非常的期待呀,同時歡迎大家加入其中,做做貢獻。

四、推薦閱讀

有意思的是pg_mooncake雖然使用的是duckdb的parquet功能,但是在某些場景下甚至能做到比duckdb還要更快是因為他們做了大量的優化,技術拉滿。

文章鏈接:https://www.mooncake.dev/blog/duckdb-parquet

官方博客:https://www.mooncake.dev/blog

五、聲明

若文中存在錯誤或不當之處,敬請指出,以便我進行修正和完善。希望這篇文章能夠幫助到各位。

文章轉載請聯系,謝謝合作。

六、本公眾號pg文章推薦

(我近期的開源之旅)

(看懂PostgreSQL where子句中表達式的先后執行順序)

特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相關推薦
熱點推薦
闊別7年,姜文攥了一個全明星局!《你行!你上!》官宣定檔

闊別7年,姜文攥了一個全明星局!《你行!你上!》官宣定檔

現代快報
2025-06-25 17:07:20
太實誠了!38歲劉亦菲不化妝無美顏純素顏出鏡,氣血充足,真美啊

太實誠了!38歲劉亦菲不化妝無美顏純素顏出鏡,氣血充足,真美啊

清游說娛
2025-06-24 17:47:37
705分奪魁!695分登頂!2025河北高考高分段“井噴”!

705分奪魁!695分登頂!2025河北高考高分段“井噴”!

童言不輕
2025-06-25 15:27:47
六年前因批評鴻茅藥酒,被跨省追捕的醫學碩士,今生命進入倒計時

六年前因批評鴻茅藥酒,被跨省追捕的醫學碩士,今生命進入倒計時

素衣讀史
2024-12-25 11:12:50
歐豪,第二個謝霆鋒!

歐豪,第二個謝霆鋒!

宛沐
2025-06-25 16:00:07
清華學霸殺妻再開庭:早已感情破裂,大量細節披露,最后影像曝光

清華學霸殺妻再開庭:早已感情破裂,大量細節披露,最后影像曝光

壹月情感
2025-06-24 23:22:10
三笘薰與妻子在鐮倉舉辦婚禮,多名日本國腳出席

三笘薰與妻子在鐮倉舉辦婚禮,多名日本國腳出席

懂球帝
2025-06-25 11:08:47
湖南高分段600分以上1.8萬考生,為何難上湖大? 如何突圍報志愿?

湖南高分段600分以上1.8萬考生,為何難上湖大? 如何突圍報志愿?

戶外小阿隋
2025-06-25 16:01:36
賺麻了!當初綠軍8換2得到霍勒迪、波神,送出的球員發展如何?

賺麻了!當初綠軍8換2得到霍勒迪、波神,送出的球員發展如何?

大衛的籃球故事
2025-06-25 20:25:27
江青警衛回憶:雖沒有抱過外孫,卻不是沒有感情,跪求主席救李訥

江青警衛回憶:雖沒有抱過外孫,卻不是沒有感情,跪求主席救李訥

紀實文錄
2025-06-25 16:39:32
互聯網公司現海王總監,一人擁有200美女

互聯網公司現海王總監,一人擁有200美女

清暉有墨
2025-06-25 12:48:59
局地11級左右雷暴大風或弱龍卷!江蘇發布預警

局地11級左右雷暴大風或弱龍卷!江蘇發布預警

環球網資訊
2025-06-25 19:04:13
湖南某幼兒園監控下最觸目驚心的一幕:病態群體,早該曝光了

湖南某幼兒園監控下最觸目驚心的一幕:病態群體,早該曝光了

小椰子專欄
2025-06-25 13:04:17
這瓶“沒貼標簽”的水,出自山姆和農夫山泉的聯手

這瓶“沒貼標簽”的水,出自山姆和農夫山泉的聯手

中國商報
2025-06-25 13:58:08
外資藥企大批退出中國,真的是咱們贏了嗎?大謬!

外資藥企大批退出中國,真的是咱們贏了嗎?大謬!

未央看點
2025-06-24 01:32:07
黃埔拆遷戶:哭!我拿著250萬房票,買不到房

黃埔拆遷戶:哭!我拿著250萬房票,買不到房

童童聊娛樂啊
2025-06-25 14:39:54
博主探店一碗面558元還要收筷子費?杭州面館店長:明碼標價,配合拍4小時反遭網暴

博主探店一碗面558元還要收筷子費?杭州面館店長:明碼標價,配合拍4小時反遭網暴

瀟湘晨報
2025-06-24 12:31:54
烏克蘭量產新型彈道導彈 稱將給俄羅斯帶來新“驚喜”

烏克蘭量產新型彈道導彈 稱將給俄羅斯帶來新“驚喜”

財聯社
2025-06-25 19:52:08
北京一直在偷偷地救市

北京一直在偷偷地救市

地產八卦女
2025-06-25 17:44:41
研究預測:大批超級富翁將離開歐洲,前往…...

研究預測:大批超級富翁將離開歐洲,前往…...

萍聚德國
2025-06-25 00:17:45
2025-06-25 21:19:00
開源中國 incentive-icons
開源中國
每天為開發者推送最新技術資訊
7149文章數 34424關注度
往期回顧 全部

科技要聞

小米YU7已下線500輛展車 26日前運往全國

頭條要聞

與汪峰節目牽手引猜測 寧靜談擇偶標準:他不是我的菜

頭條要聞

與汪峰節目牽手引猜測 寧靜談擇偶標準:他不是我的菜

體育要聞

山西太原大媽,在NBA闖出一片天

娛樂要聞

向佐接機郭碧婷,全程無交流像陌生人

財經要聞

免除蘇寧易購5億債務的神秘人是誰?

汽車要聞

售14.99萬/限量200臺 別克昂科威S新增丹霞紅內飾

態度原創

房產
時尚
親子
教育
軍事航空

房產要聞

三亞頂豪!內部資料曝光!

挑對耳環=開掛!這15款巨in巨高級,太顯臉小了!

親子要聞

終于見面啦!!!!原創dy:@辣炒年糕

教育要聞

暑假趕緊讓孩子讀這些范文

軍事要聞

伊朗總統:12天戰爭結束 重建工作開啟

無障礙瀏覽 進入關懷版 主站蜘蛛池模板: 阜新市| 新河县| 东乌珠穆沁旗| 伊吾县| 任丘市| 博兴县| 台中市| 周宁县| 丰原市| 肇东市| 鄂州市| 中超| 蒲城县| 郓城县| 厦门市| 濉溪县| 株洲县| 耒阳市| 玉树县| 枣阳市| 友谊县| 兴山县| 扎赉特旗| 永仁县| 右玉县| 翼城县| 武威市| 镇安县| 遵义县| 广西| 蓬莱市| 江都市| 阳原县| 兴城市| 罗定市| 浦县| 额尔古纳市| 木兰县| 武隆县| 封丘县| 晋州市|