关于复杂数据结构从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方式解决。

相关推荐
是一个Bug6 小时前
声明式事务:深度解析与实战指南
数据库·oracle
星光一影6 小时前
美容/心理咨询/问诊/法律咨询/牙医预约/线上线下预约/牙医行业通用医疗预约咨询小程序
mysql·小程序·vue·php·uniapp
laocooon5238578866 小时前
C#二次开发中简单块的定义与应用
android·数据库·c#
不穿格子的程序员6 小时前
Redis篇4——Redis深度剖析:内存淘汰策略与缓存的三大“天坑”
数据库·redis·缓存·雪崩·内存淘汰策略
IT枫斗者6 小时前
Netty的原理和springboot项目整合
java·spring boot·后端·sql·科技·mysql·spring
Fine姐6 小时前
数据结构03——树
数据结构
hans汉斯6 小时前
【软件工程与应用】平移置换搬迁系统设计与实现
数据库·人工智能·系统架构·软件工程·汉斯出版社·软件工程与应用
gugugu.6 小时前
Redis List类型完全指南:从原理到实战应用
数据库·redis·list
Hello.Reader6 小时前
Flink SQL ALTER 语句在线演进 Table/View/Function/Catalog/Model
数据库·sql·flink