关于复杂数据结构从MySQL迁移到PostgreSQL的可行性

1、 数据结构

存储西瓜的数据结构,需要对下列数据执行 添加、删除、修改、查询、导入、导出、复制(整体复制、复制其中一个模式)、版本比对、抽取块参数等操作,以及后续扩展块参数、扩展块参数中具体参数。

数据结构样例:

复制代码
{
 "id":"自增id"
  "name": "名称",
  "data": {
    "version": "版本号",
    "Watermelon_name": "QL-1",
    "mode_params": [
      {
        "mode": "麒麟",
        "color": "颜色",
        "texture": "纹理",
        "shape": "形状",
        "params": {
          "color_params": {
            "id": "标识",
            "code": "代号"
          },
          "texture_params": {
            "atten": "日光"
          },
          "shape_params": {
            "dev1_params": {
              "common_params": {
                "work_mode": "椭圆"
              },
              "common1_params": {
                "bit_rate": "生长周期"
              }
            }
          }
        }
      },
      {
        "mode": "黑美人",
        "color": "颜色",
        "texture": "纹理",
        "shape": "形状",
        "params": {
          "color_params": {
            "id": "标识",
            "code": "代号"
          },
          "texture_params": {
            "atten": "日光"
          },
          "shape_params": {
            "dev1_params": {
              "common_params": {
                "work_mode": "椭圆"
              },
              "common1_params": {
                "bit_rate": "生长周期"
              }
            }
          }
        }
      },
{
        "mode": "硒砂瓜",
        "color": "颜色",
        "texture": "纹理",
        "shape": "形状",
        "params": {
          "color_params": {
            "id": "标识",
            "code": "代号"
          },
          "texture_params": {
            "atten": "日光"
          },
          "shape_params": {
            "dev1_params": {
              "common_params": {
                "work_mode": "椭圆"
              },
              "common1_params": {
                "bit_rate": "生长周期"
              }
            }
          }
        }
      },
     {
        "mode": "早春红玉",
        "color": "颜色",
        "texture": "纹理",
        "shape": "形状",
        "params": {
          "color_params": {
            "id": "标识",
            "code": "代号"
          },
          "texture_params": {
            "atten": "日光"
          },
          "shape_params": {
            "dev1_params": {
              "common_params": {
                "work_mode": "椭圆"
              },
              "common1_params": {
                "bit_rate": "生长周期"
              }
            }
          }
        }
      }
    ]
  }
}

2、 MySQL和PostgreSQL处理该数据结构的比对

2.1 当前表结构与 PG数据结构的比对

当前MySQL通过5张表实现上述功能,西瓜版本表、西瓜描述表、西瓜A模式表、西瓜B模式表、西瓜C模式表。

采用PG后采用 西瓜版本表、西瓜内容表。

采用PG的优点在于,

其一 MySQL5张表互有连接,且查询西瓜模式表时,需要先查询西瓜版本表和西瓜描述表才能对后续表做定位,新增、导入等操作也需要执行多条sql,操作复杂。而PG使用JSON操作即可,最多两级查询;

其二 扩展性上 当增加块参数或者增加块参数中的具体参数,需要将数据导出,操作实际的back.sql,再进行导入。而PG执行JSON的插入操作即可。

2.2 MySQL和PG同时使用JSON存储数据结构的比对

1)、查询语法繁琐:要查询数组里的对象,必须使用 JSON_EXTRACT 配合复杂的路径,或者在 8.0+ 使用 JSON_TABLE 把 JSON 展开成虚拟表,SQL 语句会写得非常长且难懂。

2)、性能瓶颈:如果你直接查 JSON_EXTRACT(data, '$.mode_params[0].params...'),MySQL 无法使用索引(除非你提前建好虚拟列)。

3)、虚拟列维护噩梦:如果你有几百颗,且查询条件可能变(今天查 黑美人,明天查 麒麟),你无法为每一个可能的路径都创建虚拟列。一旦没建索引,查询就是全表扫描,几百颗星的数据量虽然不大,但 JSON 解析的 CPU 开销会很高。

3、实验环境

python+fastapi+TORTOISE_ORM

4、 PG 对JSON 操作

| `->` | 获取 JSON 对象的值 | `data->'name'` | 结果带引号,仍是 JSON 类型 |
| `->>` | 获取 JSON 对象的文本值 | `data->>'name'` | 结果不带引号,是文本 |
| `#>` | 按路径获取 JSON 对象 | `data#>'{a,b}'` | 等同于 `data->'a'->'b'` |
| `#>>` | 按路径获取文本值 | `data#>>'{a,b}'` | 最常用,用于获取深层嵌套的值 |
| `jsonb_array_elements()` | 展开 JSON 数组 | `jsonb_array_elements(arr)` | 把数组变成多行,用于查询数组内部 |

4.1 查询 json中的字符串

复制代码
SELECT name, data->>'version' AS a_version FROM student;

4.2 查询 json中的jsonarry

复制代码
#单个箭头是取出json
SELECT name, data->'mode_params' AS mode_params FROM student;

4.3 查询 json中的jsonobject

复制代码
SELECT name, data->'mode_params'->0->'params' AS params FROM student;

4.4 查询 json中的jsonobject中的字符串

复制代码
SELECT name, data->'mode_params'->0->'params'->'system_params'->'task_id' AS params FROM student;

4.5 修改参数

postgresql 通过mode = 高速数传 freBand = x 去匹配修改system_params中的task_id 为rc002

复制代码
UPDATE satellites
SET data = jsonb_set(
    data, 
    '{mode_params}', -- 路径:我们要替换整个 mode_params 数组
    (
        SELECT jsonb_agg(
            -- 3. 重新将处理后的元素聚合成一个新的 JSON 数组
            CASE 
                -- 1. 找到符合条件的元素(mode=高速数传 且 freBand=X)
                WHEN elem->>'mode' = '高速数传' AND elem->>'freBand' = 'X' THEN
                    -- 2. 修改这个元素:更新其内部的 system_params.task_id
                    jsonb_set(
                        elem, 
                        '{params,system_params,task_id}', 
                        '"rc002"' -- 这里填你要更新的值,注意必须是 JSON 格式(带引号)
                    )
                ELSE
                    -- 不符合条件的元素,保持不变
                    elem
            END
        )
        FROM jsonb_array_elements(data->'mode_params') AS elem 
        -- 从原数据中取出 mode_params 数组并展开
    )
)
-- 可选:加一个 WHERE 条件,确保该数组中确实包含我们要找的对象,提高效率
WHERE data @> '{"mode_params": [{"mode": "高速数传", "freBand": "X"}]}';

//查询 结果

4.6 扩展参数

复制代码
UPDATE student
SET data = jsonb_set(
    data, 
    '{mode_params}', 
    (
        SELECT jsonb_agg(
            elem || '{"new_key": "new_value"}' -- 使用 || 操作符合并 JSON
        )
        FROM jsonb_array_elements(data->'mode_params') AS elem
    )
)

5、 PG 总结

对于新手来说,PG修改SQL比较难上手,需要有一定的基础,并且使用时需要注意使用GIN以提高索引效率。

但对于本类数据结构,PG在查询块参数,扩展方面有绝对优势,针对修改局部参数SQL情形复杂的问题,采用前台发过来的数据整体覆盖旧JSON方式解决。

相关推荐
y = xⁿ6 小时前
MySQL八股知识合集
android·mysql·adb
一个爱编程的人6 小时前
一个数是不是素数
数据结构·算法
稀饭过霍6 小时前
数据类型【TINYINT、SMALLINT、INT、BIGINT、decimal(18,2)】表示意思
数据库
俺不要写代码7 小时前
数据库:DML
数据库·oracle
这个DBA有点耶7 小时前
两张百万级大表JOIN跑崩了?试试这3招
数据库·代码规范
忡黑梨7 小时前
eNSP_从直连到BGP全网互通
c语言·网络·数据结构·python·算法·网络安全
IntMainJhy7 小时前
「Flutter三方库sqflite的鸿蒙化适配与实战指南:从入门到踩坑的本地数据库开发全记录」
数据库·flutter·华为·信息可视化·数据库开发·harmonyos
counting money7 小时前
Spring框架基础(依赖注入-全注解形式)
java·数据库·spring
计算机安禾7 小时前
【Linux从入门到精通】第33篇:数据库MySQL/MariaDB安装与基础调优
linux·数据库·mysql
瀚高PG实验室7 小时前
ERROR: invalid input syntax for type integer: “a“
数据库·瀚高数据库