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

相关推荐
Luna-player8 小时前
那个在DG数据库中将多行指定字段的文本替换操作
数据库
それども8 小时前
MySQL 执行计划中 filtered = 100 是什么意思
数据库·mysql
独自破碎E8 小时前
链表中的节点每k个一组翻转
数据结构·链表
技术净胜8 小时前
Python 连接 MySQL 数据库步骤
数据库·python·mysql
厦门辰迈智慧科技有限公司8 小时前
城市地下管网全域监测与安全防控整体解决方案
数据库·安全·物联网解决方案·地下管网监测·城市地下管网监测
小肖爱笑不爱笑8 小时前
JDBC Mybatis
数据库·mybatis
cookqq9 小时前
MySQL 5.7 大表删除部分数据:.ibd 文件会变小吗?磁盘会释放吗?
数据结构·数据库·mysql
IT 行者9 小时前
告别硬编码!Spring Boot 优雅实现 Controller 路径前缀统一管理
数据库·spring boot·python
D_FW9 小时前
数据结构第三章:栈、队列与数组
数据结构·算法
小张程序人生9 小时前
一篇文章快速入门ShardingJDBC
mysql