V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
Richard14
V2EX  ›  Python

用了一段时间的 SQLAlchemy,感受到的只有混沌和混乱

  •  
  •   Richard14 · 2021-12-07 04:45:57 +08:00 · 6107 次点击
    这是一个创建于 1085 天前的主题,其中的信息可能已经有所发展或是发生改变。

    作为一个初学者,最近带着学习的目的用了一段时间,因为我本人水平比较菜,本文无意对 sqlalchemy 提出任何批评,只是描述一些我使用中遇到的问题。

    我没有什么 orm 使用经验,因为我司涉及的业务往往是大连表复杂查询,感觉 orm 不能带来多大的节省脑力的优势。平常我们业务中使用数据库,脱离开增删改查之外,更多的脑细胞应该是耗费在数据库储存原理上,如何规划数据和优化性能本身,虽然这部分花费的时间应该是最少。我从未想到有一天自己能在增删改查上耗费这么多的精力。

    SQLAlchemy 在我这个初学者看来有若干明显问题,其中主要的就是设计上的混乱。随着新版本更新后,sqlalchemy 的世界(按我的划分),应该有三种分类方法,他们分别是

    1. ORM 和原生的区别。一个 orm 同时支持原生 sql 语言完全可以理解,支持原生混用也还可以接受,但是再复杂呢?
    2. 同步和异步的差异。2022 年已经快到了,使用异步代码访问数据库完全不是什么行为艺术,而是非常正当和迫切的需求。
    3. 1.0 和 2.0 风格的差别。据我观察它写的不是那么好的文档,sqlalchemy 有过一次语法设计上的大升级。

    这三者组合之下就形成了 8 种搭配。从同步的->原生的->1.0 风格的代码,到异步的->ORM 的->2.0 式的调用,不一而足。在学习过程中文档本身就没有避免这种混乱,而有任何问题搜寻网络资料的话就更不一而足了。由于这是一个跨时间很长的项目,历史资料往往不能起到帮助,有时甚至会起到误导作用。而且作为 2022 年的项目,自然要尽可能地保证设计风格统一,就算网上找来一段代码可以 work ,如果它来自于不同的设计思路,融合进项目真的是好主意吗?

    根据我的观察,ORM 还是很有必要的东西,包括虚拟的连接层,实际上起到的是数据库本身的内存优化的作用。在需要频繁读写业务数据的时候除了降低程序员心智开销,另一方面也能实打实地提高负载能力。但是我真的想吐槽这两天在网上找到的混乱的资料,还有让人一眼读不懂的文档,以及迁移到异步只给了一篇寥寥的说明,让我完全无法 get 到它的设计精神,以至于很多问题不能通过直觉解决,而网上的资料又全部过期。。

    另外还有就是我作为初学者对于 ORM 的数据同步真的很疑惑,按照它的设计我无法理解数据同步是在哪里发生的,什么时候显式地发生,什么时候又隐式地发生,我在多端同时操作时什么时候需要注意脏读脏写问题。。。

    总之我无意批评 sqlalchemy ,我知道所有的问题都是因为我太菜了,人家肯定有解决方案。但是用的这几天感觉是真的头大。。

    第 1 条附言  ·  2021-12-07 17:33:41 +08:00
    原文有歧义贴个条,复杂 sql 查询是原先项目的,并不是因为要复杂查询才使用 orm ,楼下回复中发现很多人对此理解错误。现在使用 orm 是想要利用其快速开发的优势,但是即使进行最简单的增删改查,比如一个简单的 join+where+count ,在异步环境下用 2.0 风格实现查了半天不知道怎么搞,真的头大
    42 条回复    2021-12-07 19:58:30 +08:00
    thedrwu
        1
    thedrwu  
       2021-12-07 05:07:07 +08:00 via Android
    哈哈哈,我有类似的体验,但是知道说出来就会被人喷
    alexkkaa
        2
    alexkkaa  
       2021-12-07 08:04:37 +08:00 via Android
    这个库硬是把 py 写成了 java
    sagaxu
        3
    sagaxu  
       2021-12-07 08:13:10 +08:00 via Android
    orm 引入了复杂度,降低了性能,单表 CRUD 或者两三个表联表的简单查询还能用用
    coreki
        4
    coreki  
       2021-12-07 08:31:02 +08:00
    只能简单 crud ,复杂一点还是要用原生 sql
    WangBold
        5
    WangBold  
       2021-12-07 08:37:18 +08:00
    没错,越用越蚌埠住。
    0Zed
        6
    0Zed  
       2021-12-07 08:40:45 +08:00
    同感
    ospider
        7
    ospider  
       2021-12-07 08:40:47 +08:00   ❤️ 2
    > 根据我的观察,ORM 还是很有必要的东西,包括虚拟的连接层,实际上起到的是数据库本身的内存优化的作用。
    仔细看文档吧, 之所以分成 core 和 orm 两个层次就是为了让你可以只用链接池这种基础组件, 而不用全部都用.

    > 很多问题不能通过直觉解决,而网上的资料又全部过期。。
    SQLAlchemy 能查到的资料确实有很多过期的, 但是还是比较好分辨和转换的吧, 基本看到带 query 的代码就是老风格的, 其他的就是 1.4/2.0 风格的.

    > 我司涉及的业务往往是大连表复杂查询,感觉 orm 不能带来多大的节省脑力的优势。
    CRUD 比较适用 ORM, LDAP 你用啥 ORM...裸写 SQL 才是正途, 不过像上面说的, 依然可以用到 core 部分.

    > 使用异步代码访问数据库完全不是什么行为艺术,而是非常正当和迫切的需求。
    同步和异步比较混乱是 Python 的锅, SQLAlchemy 不背
    raptor
        8
    raptor  
       2021-12-07 08:58:12 +08:00
    我们只用 core 的部分,还是很爽的。简单 crud 部分少量使用 orm 也很灵活方便。但如果想全部用 ORM 那的确会比较困难……然而哪个 ORM 不困难呢?
    sadfQED2
        9
    sadfQED2  
       2021-12-07 09:01:37 +08:00 via Android
    😂😂我也同感,最后不用了,但是我不敢说,怕被人喷人菜怪框架
    makelove
        10
    makelove  
       2021-12-07 09:25:25 +08:00
    因为不喜欢这类 ORM 风格和增加没必要复杂性(相对于简单的 sql ),所以我直接写了自己的 ORM ( 1500 行左右代码)。

    其实我的核心要求就很简单:
    1 和自定义 class 绑定以便在数据行上写逻辑,这也是各类 ORM 的最大好处
    2 查询字段强类型
    3 基本 CRUD 以覆盖大部分日常 sql 操作
    在 sql 上面搞出非常复杂的对象关系、查询都是无谓地增加复杂性
    RangerWolf
        11
    RangerWolf  
       2021-12-07 09:31:51 +08:00
    我自己就推荐使用 sqlalchmey 来帮忙维护连接池,其他地方全是裸写 SQL
    Huelse
        12
    Huelse  
       2021-12-07 10:06:04 +08:00
    我的 sqlalchmey 就是个池子管理员
    fgwmlhdkkkw
        13
    fgwmlhdkkkw  
       2021-12-07 10:36:30 +08:00
    我自己写了一个,不过还没有文档
    https://github.com/zzztttkkk/orm
    ebingtel
        14
    ebingtel  
       2021-12-07 10:41:42 +08:00
    看了一下 api 文档,感觉函数命名风格都不统一,就劝退了……peewee 真香
    flniu
        15
    flniu  
       2021-12-07 10:51:08 +08:00
    SQLAlchemy 是基于 data mapper pattern 的 ORM 。如果是复杂查询比较多的业务,不如试试基于 active record pattern 的 ORM ,比如 Peewee 。
    flniu
        16
    flniu  
       2021-12-07 10:53:04 +08:00
    用 Peewee 基本上思维方式跟原生 SQL 很像。而 ORM 又帮你解决了连接管理、防范 SQL 注入的问题。
    so1n
        17
    so1n  
       2021-12-07 11:12:59 +08:00
    我都是裸写 sql 的, 在 ide 的帮助下裸写 sql 很爽, 当然在一些后台管理的需求我还是会使用 orm
    adoal
        18
    adoal  
       2021-12-07 11:33:37 +08:00
    “大连表复杂查询”,会不会被分词引擎分出一股海蛎子味来……
    adoal
        19
    adoal  
       2021-12-07 11:38:12 +08:00
    从你自己写的就可以看出来,更多的问题是因为,1.项目演进的问题 2.SA 跟你的项目的匹配度问题

    至于 SA 本身的设计路线,当然也是个问题,但并不是跟你带来痛苦的关键
    adoal
        20
    adoal  
       2021-12-07 11:43:24 +08:00
    建议:
    1. 因为项目跨度太长,必然会产生屎山和各种风格不一致,还是调整心态吧。
    2. 虽然“2022 年已经快到了,使用异步代码访问数据库完全不是什么行为艺术”,但项目不是 2022 年开始的,是周期长跨度到 2022 年的,不要给自己找麻烦去迁移异步了。如果是新项目可以。
    3. 既然是海蛎子查询,那还是现实一点吧。
    xhinliang
        21
    xhinliang  
       2021-12-07 11:43:43 +08:00
    确实很恶心,给初学者带来了极大的不便。
    adoal
        22
    adoal  
       2021-12-07 11:44:44 +08:00
    @ospider LDAP……是想说 OLAP 吧
    zhuangzhuang1988
        23
    zhuangzhuang1988  
       2021-12-07 12:14:56 +08:00
    同。
    SmiteChow
        24
    SmiteChow  
       2021-12-07 14:28:19 +08:00
    那是你没掌握到 sqlalchemy 的精髓,如同元编程。
    jakehu
        25
    jakehu  
       2021-12-07 15:07:40 +08:00
    只用 Core 部分功能,还挺好的
    jiezhi
        26
    jiezhi  
       2021-12-07 15:12:02 +08:00
    只想说 py 每次配置 MySQL 的驱动都是一头脑。。。 装了一堆,最后也不知道是哪个能用了
    cclin
        27
    cclin  
       2021-12-07 15:14:03 +08:00
    @adoal
    ```
    {
    "code":0,
    "data":[
    {
    "nature":"nt",
    "word":"大连表"
    },
    {
    "nature":"ad",
    "word":"复杂"
    },
    {
    "nature":"v",
    "word":"查询"
    }
    ]
    }
    ```
    hanlp yyds
    nikan999
        28
    nikan999  
       2021-12-07 15:15:41 +08:00
    @SmiteChow 能分享下 sqlalchemy 的精髓吗? 我用过 django sqlalchemy peewee, sqlalchemy 的学习曲线是最高的,但是带给我的收益不是很大,更多时候我需要一个连接池+ 快速上手的 crud
    jjx
        29
    jjx  
       2021-12-07 15:24:44 +08:00
    这段感觉已经回复过 n 次了一样

    sqlalchemy 的两个层次, orm, sql expression

    如果要可控性,建议只使用 sql expression

    sql expression 让你用 python 写 sql , 个中体验,得深入了解才行

    开发 erp 或企业软件的, 别说手写 sql! 一个复杂的 erp 报表可能几百行, 用 sql 的维护那个心酸

    如果你灵活用 sqlalchemy 的 sql expression 重写, 直接代码降 n 倍而且重用
    ipwx
        30
    ipwx  
       2021-12-07 15:26:38 +08:00
    @nikan999 简单的 ORM 不妨试试这个 https://sqlmodel.tiangolo.com/

    对 SQLAlchemy 的二次包装
    ipwx
        31
    ipwx  
       2021-12-07 15:27:20 +08:00
    @nikan999 SQLAlchemy 最大的吸引力是,随便切换 Backend 基本改改都能整个跑通。

    不像裸 SQL 那换后端就是大工程。
    nikan999
        32
    nikan999  
       2021-12-07 15:44:29 +08:00
    @ipwx 这个有听过 ,fastapi 作者写的, 还有一个是 records https://github.com/kennethreitz/records 也是基于 SQLAlchemy
    以前 python 有项目需要支持各数据库的时候 也用的是 SQLAlchemy
    但是我再去翻 SQLAlchemy 文档,还是感觉很难一下子就找到我需要的一些东西
    nikan999
        33
    nikan999  
       2021-12-07 15:49:17 +08:00
    @ipwx 比如我需要 quickstart 和 FAQ 只需要 3-4 页的基本示例就能让项目快速跑起来,其它项目基本都有,然而 SQLAlchemy 的文档就是像字典一样,要去仔细查找,engine, session ,core,orm, 如果是用 flask-SQLAlchemy 和各种基于他的库帮忙简化开发还好,但是对于一个刚接触 ORM 的人来说,这个库的曲线在我看来有点过于高了
    tabris17
        34
    tabris17  
       2021-12-07 15:50:12 +08:00
    人生苦短,我用 peewee
    zachlhb
        35
    zachlhb  
       2021-12-07 17:17:26 +08:00 via iPhone
    不得不说还是 Django orm 好用,最近还在研究 Django3 的异步,感觉 Django 足够用了
    Richard14
        36
    Richard14  
    OP
       2021-12-07 17:31:32 +08:00
    @ospider py 的异步从 3.4 加入一直更到 3.7 已经有比较稳定的 api ,文档也从最初的大杂烩到现在的条理分明,覆盖全面,反观 sqlalchemy 直接一篇不算很长的“从 1.0 迁移到 2.0”,另一篇“sqlalchemy 与 asyncio”,说明含糊不清,覆盖单一,查看附录里的范例代码发现已经在正文中看过了。混乱的就是 sqlalchmy 本身,关 python 什么锅?

    @Huelse 单纯用 orm 维护连接池有什么优势?我感觉用 core 库的连接池也一样啊
    Richard14
        37
    Richard14  
    OP
       2021-12-07 17:37:46 +08:00
    @sagaxu 简单场景下性能肯定是提高的,我看他相当于把空间复杂度提上去了,比如一个实际业务中经常有各种恶心复杂的判定,搜索一行的 a 项目,如果 a>0 则 b 项目+=1 ,如果 b 项目+=1 结束后是偶数则 c 项目=0 ,这样一连串逻辑用普通 sql+连接池实现可能需要搜索和提交多次,我看他虚拟一层之后只需要在内存内部维护,实际业务发起多次请求,它往后端的搜索和提交只有几次,大部分在内存里完成,当然性能会比入库高。只不过这也是我无法理解的一点,我无法理解当问题变成多节点以后它维护的这个虚拟层是如何保持数据同步的
    sagaxu
        38
    sagaxu  
       2021-12-07 18:54:46 +08:00 via Android
    @Richard14 一般 orm 有工作 cache ,读是从 cache 里读,写入也是写入到 cache ,多次读和多次写可能会合并。这种功能你自己写也没几行代码的,但他自动做的未必是你期望的,如果不是非常熟悉,遇到问题根本没法排查。
    wffnone
        39
    wffnone  
       2021-12-07 19:13:38 +08:00
    怎么说呢,我点进来是以为多少能看到一点稍微有一点价值的批评。

    我不想讨论技术。楼主说,「作为一个初学者」,「因为我太菜了」。你真的把自己当初学者了吗,真的觉得自己菜吗?

    这种标题,一般都是初级程序员会点进来。初级程序员交流技术,请不要交流看法,只说用法和事实就好了。
    neoblackcap
        40
    neoblackcap  
       2021-12-07 19:35:56 +08:00   ❤️ 5
    data mapper 跟 active records 是两种 orm 的设计思路。没有优劣,只有合适跟不合适。

    很多时候人家不做的功能不一定是他们懒,是有些功能本来就是几行代码的事情,库留给你自己实现。而不是强迫你接受它的实现。比如异步。
    sqlalchemy 很多功能依赖于底层同步的数据驱动,上层如果硬是要全盘走异步。那么就是需要 sqlalchemy 帮你维护线程池。但是库并不是专为你服务的,还有很多项目是不需要异步功能的。所以它留给你自己选择。而不是出厂自带。毕竟用不了几行代码封装。

    至于说自己 sql 写得好的,我见了很多其实都是“我会写 SQL”的水平,所以不要觉得自己写 sql 玩爆这些 orm 框架。当你要有一些变化的操作,你 sql 就很容易拼接起来,你真的能保证你的 sql 拼接处于一个很高的水平?这个时候也许你就走在写一个坡脚的 sql builder 或者 orm 框架的路上了。

    觉得有问题,可以多去了解项目的变迁。如果你觉得我就是一个 curd boy ,不需要了解这些工具的历史。那么我只想说你自求多福吧。或者这些工具从一开始就不适合你用。也许其他的会更好。或者你也可以自己重新写一个。
    计算机领域没有什么永恒的,有 apache web server ,也会有 nginx 。有 memcache ,也会有人去写 redis 。只不过很多人并不是写出一个更好的罢了。所以了解历史,从中汲取经验,避免掉坑也是一件好事。
    joApioVVx4M4X6Rf
        41
    joApioVVx4M4X6Rf  
       2021-12-07 19:38:26 +08:00
    @neoblackcap 说的太对了,看了五六遍简直豁然开朗
    gowk
        42
    gowk  
       2021-12-07 19:58:30 +08:00
    @neoblackcap 说的非常好
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3974 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 05:13 · PVG 13:13 · LAX 21:13 · JFK 00:13
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.