跳转至

Trino 作为多数据源统一查询层的实现方案

近期,我司在项目推进中遇到一项跨库(两个 gauss 库)查询需求。客户方现有 Trino 环境,本可通过连接该环境直接实现跨库查询,但由于历史原因(其采购的私有化 Trino 服务对应的维护团队已解散,无人接手运维,客户出于风险顾虑明确表示 “不敢动” 现有环境),该方案无法推进。

因此,为解决这一跨库查询需求,我方独立部署一套私有化 Trino 环境,以此作为替代方案实现数据跨库查询功能。

一、部署两个测试数据源

mkdir /demo-trino/{opengauss,trino} -p

1. 编写 opengauss 编排文件

cat /demo-trino/opengauss/compose.yaml

services:
  opengauss-1:
    image: opengauss/opengauss:7.0.0-RC2.B003
    container_name: opengauss-1
    ports:
      - 1234:5432
    privileged: true
    volumes:
      - ./db1_data:/var/lib/opengauss/data
    environment:
      TZ: Asia/Shanghai
      GS_PASSWORD: "!zdW4Krw8CfBLPFJ9twF0tO2NYtS1IDF"  # 设置数据库初始化密码(必须满足复杂度要求)
      GS_USERNAME: 'test1'
      GS_DB: 'postgres'
    networks:
      - trino-demo-network
  opengauss-2:
    image: opengauss/opengauss:7.0.0-RC2.B003
    container_name: opengauss-2
    ports:
      - 1235:5432
    privileged: true
    volumes:
      - ./db2_data:/var/lib/opengauss/data
    environment:
      TZ: Asia/Shanghai
      GS_PASSWORD: "!dW4Krw8CfBLPFJ9twF0tO2NYtS1IDF"  # 设置数据库初始化密码(必须满足复杂度要求)
      GS_USERNAME: 'test2'
      GS_DB: 'postgres'
    networks:
      - trino-demo-network
networks:
  trino-demo-network:
    driver: bridge

2. 启动服务

docker compose up -d

3. 插入测试数据

1. 在 DB1 数据库中创建

-- 创建订单主表(记录订单基本信息)
CREATE TABLE sales_orders (
    order_id INT PRIMARY KEY,               -- 订单ID(关联键)
    customer_id INT NOT NULL,               -- 客户ID
    order_date VARCHAR(10) NOT NULL,        -- 下单日期(字符串类型,格式:YYYY-MM-DD)
    total_amount DECIMAL(10, 2) NOT NULL,   -- 订单总金额
    payment_status VARCHAR(20) NOT NULL,    -- 支付状态:未支付/已支付/退款
    sales_region VARCHAR(50) NOT NULL       -- 销售区域
);
COMMENT ON TABLE sales_orders IS '销售订单主表,存储订单的基本信息';
COMMENT ON COLUMN sales_orders.order_id IS '订单唯一标识,作为关联其他表的主键';
COMMENT ON COLUMN sales_orders.customer_id IS '客户唯一标识,关联客户信息表';
COMMENT ON COLUMN sales_orders.order_date IS '下单日期,字符串格式存储(YYYY-MM-DD)';
COMMENT ON COLUMN sales_orders.total_amount IS '订单总金额,保留两位小数';
COMMENT ON COLUMN sales_orders.payment_status IS '支付状态,可选值:未支付/已支付/退款';
COMMENT ON COLUMN sales_orders.sales_region IS '销售区域,如华东、华北等';

-- 插入测试数据(2025年6月的订单)
INSERT INTO sales_orders (order_id, customer_id, order_date, total_amount, payment_status, sales_region)
VALUES
(1001, 101, '2025-06-05', 2999.99, '已支付', '华东'),  -- 6月5日订单
(1002, 102, '2025-06-12', 1599.00, '已支付', '华北'),  -- 6月12日订单
(1003, 103, '2025-06-18', 4599.50, '未支付', '华南'),  -- 6月18日订单
(1004, 104, '2025-06-25', 899.99, '已退款', '西北');   -- 6月25日订单


-- 验证数据
SELECT * FROM datarc.sales_orders;

2. 在 DB2 数据库中创建

-- 创建订单明细表(记录订单包含的商品明细)
CREATE TABLE sales_order_items (
    item_id INT PRIMARY KEY,                -- 明细ID
    order_id INT NOT NULL,                  -- 订单ID(与订单主表sales_orders关联)
    product_id INT NOT NULL,                -- 商品ID
    product_name VARCHAR(100) NOT NULL,     -- 商品名称
    quantity INT NOT NULL,                  -- 购买数量
    unit_price DECIMAL(10, 2) NOT NULL,     -- 单价
    subtotal DECIMAL(10, 2) NOT NULL        -- 小计金额(quantity * unit_price)
);
COMMENT ON TABLE sales_order_items IS '销售订单明细表,存储订单中包含的商品明细信息';
COMMENT ON COLUMN sales_order_items.item_id IS '明细记录唯一标识';
COMMENT ON COLUMN sales_order_items.order_id IS '关联订单主表的订单ID';
COMMENT ON COLUMN sales_order_items.product_id IS '商品唯一标识';
COMMENT ON COLUMN sales_order_items.product_name IS '商品名称';
COMMENT ON COLUMN sales_order_items.quantity IS '商品购买数量';
COMMENT ON COLUMN sales_order_items.unit_price IS '商品单价,保留两位小数';
COMMENT ON COLUMN sales_order_items.subtotal IS '商品小计金额(数量×单价)';

-- 插入测试数据(与订单主表的order_id对应)
INSERT INTO sales_order_items (item_id, order_id, product_id, product_name, quantity, unit_price, subtotal)
VALUES
(1, 1001, 1, '笔记本电脑', 1, 2999.99, 2999.99),
(2, 1002, 2, '无线耳机', 2, 799.50, 1599.00),
(3, 1002, 3, '手机壳', 1, 29.90, 29.90),  -- 订单1002总金额为1628.90(与主表保持一致)
(4, 1003, 4, '智能手表', 1, 4599.50, 4599.50),
(5, 1004, 5, '蓝牙音箱', 1, 899.99, 899.99);

-- 验证数据
SELECT * FROM sales_order_items;

3. 验证数据

验证数据
image-20250807111127322

二、部署 trino 数据源

https://trino.io/docs/current/overview.html

文件结构

root@jenkins:/demo-trino/trino# tree 
.
├── compose.yaml
├── data
└── etc
    ├── catalog
       ├── opengauss-1.properties
       └── opengauss-2.properties
    ├── config.properties
    ├── jvm.config
    └── node.properties

1. 编写 compose.yaml 文档

mkdir /demo-trino/trino/{etc,data}

mkdir /demo-trino/trino/etc/catalog

services:
  # Trino 服务
  trino:
    image: trinodb/trino:latest
    container_name: trino
    ports:
      - "8080:8080"  # Trino Web UI 和 JDBC 连接端口
    volumes:
      - ./etc:/etc/trino  # 挂载 Trino 配置文件
      - ./data:/data/trino  # 挂载数据目录
      - ./trino/etc/password-authenticator.properties:/etc/password-authenticator.properties
    environment:
      - TZ=Asia/Shanghai
    restart: unless-stopped
    networks:
      - opengauss_trino-demo-network
networks:
  opengauss_trino-demo-network:
    external: true  # 关键:声明该网络已存在,无需重新创建

2. 编写 catalog 配置

1. opengauss-1 配置

cat /demo-trino/trino/etc/catalog/opengauss-1.properties

connector.name=postgresql
connection-url=jdbc:postgresql://opengauss-1:1234/postgres
connection-user=test1
connection-password=!zdW4Krw8CfBLPFJ9twF0tO2NYtS1IDF
case-insensitive-name-matching=true

2. opengauss-2 配置

cat /demo-trino/trino/etc/catalog/opengauss-2.properties

connector.name=postgresql
connection-url=jdbc:postgresql://opengauss-2:1235/postgres
connection-user=test2
connection-password=!dW4Krw8CfBLPFJ9twF0tO2NYtS1IDF
case-insensitive-name-matching=true

3. 编写 config.properties

cat /demo-trino/trino/etc/config.properties

coordinator=true
node-scheduler.include-coordinator=true
http-server.http.port=8080
discovery.uri=http://example.net:8080

# 新增认证配置
#http-server.authentication.type=PASSWORD

cat /demo-trino/trino/etc/password-authenticator.properties

password-authenticator.name=file
file.password-file=/etc/trino/password.db

5. 创建密码

创建密码文件:

touch /demo-trino/trino/etc/password.db

添加或更新用户密码test

htpasswd -B -C 10 password.db test

4. 编写 jvm 配置

cat /demo-trino/trino/etc/jvm.config

-server
-Xmx8G
-XX:+UseG1GC
-XX:G1HeapRegionSize=32M
-XX:+UseGCOverheadLimit
-XX:+ExplicitGCInvokesConcurrent
-XX:+HeapDumpOnOutOfMemoryError
-XX:+ExitOnOutOfMemoryError

5. 编写 node.properties

node.environment=production
node.id=trino-coordinator-1
node.data-dir=/data/trino

二、使用 trino 查询

1. 进入 trino

docker compose exec -it trino trino

2. 命令查看所有已配置的数据源(CATALOGS)

SHOW CATALOGS;

trino> SHOW CATALOGS;
   Catalog   
-------------
 1-opengauss 
 2-opengauss 
 system      
(3 rows)

3. 查看 db1 下的 schemas (对应为pg中的数据库 postgres )

SHOW SCHEMAS FROM "1-opengauss" ;

4. 查看数据库中的所有表

show tables from "1-opengauss".test1;

5. 查询表数据

select * from "1-opengauss".test1.sales_orders limit 10;

6. 聚合两个库查询(跨库查询)

SELECT
    o.order_id,              
    o.customer_id,          
    o.order_date,          
    i.product_name,       
    i.quantity,            
    i.subtotal              
FROM
    "1-opengauss".test1.sales_orders o     
INNER JOIN
   "2-opengauss".test2.sales_order_items i      
    ON o.order_id = i.order_id;

经测试没问题、然后连接我方产品进行后续工作。