SQLAlchemy 比 Django 自带的 ORM 好在哪里? - V2EX
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
eyp82
V2EX    Python

SQLAlchemy 比 Django 自带的 ORM 好在哪里?

  •  
  •   eyp82 2017-02-08 04:33:02 +08:00 17568 次点击
    这是一个创建于 3174 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近看了一下 SQLAlchemy 的文档, 感觉大致的使用方式跟 Django ORM 很像(包括 Peewee 之类都很像), 就是细节上感觉有点拧巴, 不如 Django 的 ORM 那么自然. 那 SQLAlchemy 相比有哪些优势呢? 谢谢大家.

    54 条回复    2018-09-15 09:26:49 +08:00
    changwei
        1
    changwei  
       2017-02-08 06:29:20 +08:00 via Android   2
    我用过 php 下各种框架得 orm 之后觉得 python 下的 orm 都很拧巴。。。
    bigzhu
        2
    bigzhu  
       2017-02-08 08:19:17 +08:00 via Android
    早年没靠谱 orm 的时候(暴露年龄了),点了太多技能点在写 sql 上,之后觉得所有的 orm 都很拧巴。。。
    chaleaoch
        3
    chaleaoch  
       2017-02-08 08:40:11 +08:00
    说几个 django orm 坑爹的地方。
    1. 有些 group by 无法用 orm 实现。
    2. 有些连表查询,用 djanog orm 写出来的 sql 是子查询。
    3. 速度感人,一个两万条记录的查询,用时三秒。 sql<100ms

    1 和 2sqlalchemy 有很好的解决方案。
    3 我不确定 sqlalchemy 是更快还是更慢。
    chaleaoch
        4
    chaleaoch  
       2017-02-08 08:41:31 +08:00
    还有 django orm 如法实现分表。至少原生不支持。只能分区。
    sqlalchemy 支持。
    eyp82
        5
    eyp82  
    OP
       2017-02-08 08:42:53 +08:00 via iPhone
    @chaleaoch 感谢具体的体验和回复
    XhstormR
        6
    XhstormR  
       2017-02-08 08:47:07 +08:00 via Android
    @chaleaoch 所以推荐原生 SQL ,还是 ORM 呢?
    chaleaoch
        7
    chaleaoch  
       2017-02-08 08:54:45 +08:00
    @XhstormR 该用 orm 还是得用 orm 毕竟方便。一直都用 sql 有两个问题,一个是预防 sql 注入,另一个是代码不易读。
    precisi0nux
        8
    precisi0nux  
       2017-02-08 09:25:35 +08:00 via iPhone
    @changwei 毕竟是世界上最好的语言。
    est
        9
    est  
       2017-02-08 09:27:14 +08:00   2
    sqlalchemy 怎么评价呢,首先说,功能完善整齐

    然后就是 1 楼所说的,拧巴!没错!有的时候真行想自己去撸 sql 。。 orm 是一种思维和开发的负担。难写难维护难调试


    sqlalchemy 的问题,用一句话表示:

    from sqlalchemy.orm import joinedload, Load, load_only

    你看,这里面包含了不含下划线全小写风格,驼峰风格,下划线风格三种 style 。真是玩死你系列。
    TangMonk
        10
    TangMonk  
       2017-02-08 09:30:42 +08:00
    ActiveRecord 路过。。
    vicalloy
        11
    vicalloy  
       2017-02-08 09:52:17 +08:00
    没用过 SQLAlchemy ,不是很了解。
    很早之前简单的了解过 SQLAlchemy ,从 API 的友好度上看 Django 的 ORM 比 SQLAlchemy 好很多(个人看法)。
    Django 的 ORM 调优其实并不是很难,很多时候慢是因为用的不对(糟糕的 SQL 一样慢)。
    当然,在极少数情况下还是会出现 ORM 无能为力的情况,这时候可以直接写 SQL 。 ORM 和 SQL 并不冲突。为了这 0.x%的情况而放弃使用 ORM 很没必要。
    @chaleaoch
    1. Django 的查询可以嵌入 SQL ,也可以把自己手写的 SQL 绑定到对象上。
    不知道你遇到的具体情况是怎么样的,不过在我看来第一条应当是可以实现。
    2. 有些表连接写出来是子查询,这个需要结合具体案例,不是很确定是否是写法问题。
    3. 2w 条数据查询用时 3 秒,这个非常不正常,需要结合具体代码进行分析。从我主观角度看是代码写的有问题。
    zhouquanbest
        12
    zhouquanbest  
       2017-02-08 10:04:40 +08:00
    以前只用 SQLAlchemy 现在用 Peewee 感觉 API 更友好
    xiaket
        13
    xiaket  
       2017-02-08 10:16:32 +08:00
    我和你的感觉是一样的, Django 的 ORM 的易读性比 peewee 好一圈, peewee 的易读性比 SA 好两圈或更多...
    est
        14
    est  
       2017-02-08 12:17:57 +08:00
    @zhouquanbest peewee 坑多。主要与原因是 too young

    @xiaket 赞同。

    django 的 orm 其实挺好的。应付 90% 的逻辑没问题,读起来改起来都比 sql 容易太多。
    anjianshi
        15
    anjianshi  
       2017-02-08 12:23:50 +08:00
    sqlalchemy 硬着头皮用了一段时间,实在研究不下去,改用 peewee 了。
    用 peewee ,哪里碰到了问题直接去查源码,主体就一个 python 文件,感觉代码思路很清晰,碰到的大部分问题都得以解决了。
    用 sqlalchemy 的时候想查源码都查不出个头绪来
    xiaket
        16
    xiaket  
       2017-02-08 12:30:10 +08:00
    @est 个人曾经想过把 Django 的 ORM 完全剥离出来,这样就可以脱离 Django 使用,后来看到 peewee 就放弃了... 不是说它做得有多好,不过至少是存在了.
    loading
        17
    loading  
       2017-02-08 12:37:02 +08:00 via Android
    sqlalchemy 很多语言都有实现,换语言,换库都能直接上手。
    sagaxu
        18
    sagaxu  
       2017-02-08 13:04:56 +08:00
    @est 那是 PEP8 规定的命名方式
    chaleaoch
        19
    chaleaoch  
       2017-02-08 13:15:09 +08:00
    @vicalloy
    @chaleaoch
    1. Django 的查询可以嵌入 SQL ,也可以把自己手写的 SQL 绑定到对象上。
    不知道你遇到的具体情况是怎么样的,不过在我看来第一条应当是可以实现。
    ====
    django orm 是有 extra 的写法,不过我把这种写法归于直接 sql 一类。(也是我个人观点)
    2. 有些表连接写出来是子查询,这个需要结合具体案例,不是很确定是否是写法问题。
    3. 2w 条数据查询用时 3 秒,这个非常不正常,需要结合具体代码进行分析。从我主观角度看是代码写的有问题。
    ====
    非常简单 <model>.objects.all().values() 三秒
    <model>.objects.filter(<这里假设出 10000 条数据>).values() 一秒
    直接用客户端查询 select * from <table name> <100ms

    我的理解问题出在 django orm 在生成映射结构的时候多处使用 for 循环导致的这个问题。
    xiaket
        20
    xiaket  
       2017-02-08 13:35:46 +08:00
    @chaleaoch 不给 ORM 翻译出来的 SQL 就和裸 SQL 比较性能并猜测原因略有些耍流氓...
    vicalloy
        21
    vicalloy  
       2017-02-08 14:03:23 +08:00   2
    @chaleaoch
    你可以再测试一下,<model>.objects.all().values() 绝对花不了 1 秒。
    Django 的 QuerySet 是 Lazy 的,只有在你用的时候才会发生查询。
    单纯执行上面的语句不会执行 SQL 。
    如果你的写法是
    >>> qs = <model>.objects.all().values()
    >>> list(qs)
    超过 1s 是很正常的,因为你要把所有数据一次性取出来。你可以用调试工具看一下,生成的 SQL 就是`select * from <table name>`,查询速度本身是非常快的,但单 2w 条数据,别的不说,单网络传输都要费不少时间。

    使用 Django 的 ORM ,如果慢的不正常,用调试工具看一下生成的 SQL ,通常都可以解决。所谓必须写 SQL 的地方极少。注:
    - 部分复杂报表,查询速度慢,用 ORM 性能优化有些难做。
    - 需要用到数据库专有特性, Django 不支持,需要用 extra 内嵌少量 SQL 。
    Jordan
        22
    Jordan  
       2017-02-08 14:03:36 +08:00 via Android
    SA 不适合初学者,以及一直用一种数据库的开发者。要驾驭好必须对 rmdb 有一定程度的认识,为了在不同数据库间充分利用他们的特性,并提供一致的接口, SA 没少下功夫,所以代码比其他 ORM 难读。 SA 不仅仅是 ORM 。
    wangfengmadking
        23
    wangfengmadking  
       2017-02-08 14:35:01 +08:00
    我只想说 SQLAlchemy 生成真正的 SQL 语句那就是灾难,性能的坑太多了。。。我觉得还是自己撸个简单的 ORM 比较好,我最新的项目就是这么干的, sql 执行效率杠杠的
    t0p10
        24
    t0p10  
       2017-02-08 15:04:16 +08:00
    直接手写 SQL 运行速度比 ORM 快很多
    ManjusakaL
        25
    ManjusakaL  
       2017-02-08 15:16:41 +08:00
    Django 的 ORM 事务和多库支持简直鸡肋。。。
    chaleaoch
        26
    chaleaoch  
       2017-02-08 15:20:55 +08:00
    @vicalloy
    对,是我没说清楚.
    我就是这个意思
    >>> qs = <model>.objects.all().values()
    >>> list(qs)
    超过 1s 是很正常的,因为你要把所有数据一次性取出来。你可以用调试工具看一下,生成的 SQL 就是`select * from <table name>`,查询速度本身是非常快的,但单 2w 条数据,别的不说,单网络传输都要费不少时间。

    你的意思是说,(超过 1s 是很正常的)这一秒钟时间并不是 orm 引起的?
    chaleaoch
        27
    chaleaoch  
       2017-02-08 15:23:52 +08:00
    @ManjusakaL 多库还行啊...用 db_router...
    chaleaoch
        28
    chaleaoch  
       2017-02-08 15:24:58 +08:00
    @wangfengmadking 要么是因为你水平到位了.要么是因为项目刚开始没多长时间.等将来业务变动自己撸的就扛不住了.
    我为什么这么说?
    以为我这么干过.(逃.
    vicalloy
        29
    vicalloy  
       2017-02-08 15:30:04 +08:00
    @chaleaoch
    对 1s 很正常,和 ORM 没关系。
    如果有 100w 条数据,你 list(qs)就不是慢的问题,内存会直接爆掉。
    你执行 SQL ,实际上只是拿到一个游标,并没有立即将所有数据全部取出来。
    你的 list(qs)实际上是一次性将数据全部取出丢到 list 里,不慢才怪。
    wizardforcel
        30
    wizardforcel  
       2017-02-08 15:35:45 +08:00
    我觉得任何 orm 都很拧巴。。

    本来把多维数据放进二维的表就够受得了,完了之后各种 sql 查询特性还支持不齐。遇到一种新的子句就要看看文档怎么实现,不同框架还不一样,难受死了。
    est
        31
    est  
       2017-02-08 16:00:19 +08:00
    @sagaxu

    pep 没问题,但是你写 orm 语句就蛋痛了。

    还是 django 或者 peewee 那种链式调用写起来舒服。

    sqlalchemy 的 .option() 各种复杂结构,各种 func 太复杂了。不值得花那么多精力去抽象。 orm 本来就一种 dsl 了, sqlalchemy 是 dsl 里再发明一个 dsl 。
    比如 primaryjoin="and_(xxx=yyy)" 这种简直丑得不要不要的。
    chaleaoch
        32
    chaleaoch  
       2017-02-08 16:14:54 +08:00
    @vicalloy
    部分认同你的观点:
    import MySQLdb

    # Open database connection
    db = MySQLdb.connect(<略>)

    import time
    starttime = time.time()
    sql0 = "select * from <略>"
    cursor = db.cursor(MySQLdb.cursors.DictCursor)
    cursor.execute(sql0)
    custom_html_data = cursor.fetchall()
    print time.time() - starttime
    cursor.close()

    我这边输出的结果在 1.6 ~ 1.7 秒之间.
    吃掉的那 1.3 秒就是 orm 的损耗.

    这里有一个不严谨的地方就是,我没有测试当前时间点 django orm 的效率.

    最后还有一个问题,如果这种时间的损耗都可以忽略的话,大家所说的 ORM 影响效率的点在哪里呢?
    sagaxu
        33
    sagaxu  
       2017-02-08 20:04:52 +08:00
    @est 那是因为 SA 支持的 DB 种类更多,而且把 ORM 和 Expression 分别抽象再组合,有时可以只用 Expression ,能力上 SA 比 Django 更为全面和强大
    lightening
        34
    lightening  
       2017-02-08 20:10:20 +08:00 via iPhone
    看了以上评论觉得果然还是 ruby 的 ActiveRecord 好用啊!
    ashin
        35
    ashin  
       2017-02-08 20:45:35 +08:00
    肤浅的认为 sqlalchemy 并没有 django 的 orm 好,是真的好难用啊,文档也乱七八糟的感觉,每次都得去看源码,有人用估计也是在不用 django 的时候 orm 方案上早期没有太多的选择,看了 peewee 的文档后觉得 peewee 的文档结构够清楚,明确的要求 connect 和 close ,很方便就实现了自动 reconnect ,轻松两行代码就可以做到主从的读写分离,用 pwiz 还可以把已有的表自省生成 model ,感觉使用 peewee 才是 python orm 正确的选择,还有 records 也不错的样子,暂时还没有在项目里用过,说的是 SQL for Humans :)
    param
        36
    param  
       2017-02-08 22:23:24 +08:00 via Android
    有没有人告诉我,什么是拧巴
    eyp82
        37
    eyp82  
    OP
       2017-02-08 22:32:22 +08:00
    看到楼上有人说 SQLAlchemy 支持的 DB 更多, 先假定这是对的. 但感觉并没什么用啊. 一般应用数据库选型定了一种后很少会换, 支持主流的 MySQL, PostgreSQL, Oracle 就可以了吧, 再多也没什么用.
    zeroten
        38
    zeroten  
       2017-02-08 22:39:13 +08:00
    哈,原来 peewee 用户挺多的
    PythonAnswer
        39
    PythonAnswer  
       2017-02-08 22:41:42 +08:00 via Android
    records 是基于 sqlalchemy 的
    Gem
        40
    Gem  
       2017-02-08 22:59:54 +08:00
    Python 里的 AR 实现: https://orator-orm.com/
    ratazzi
        41
    ratazzi  
       2017-02-09 09:01:28 +08:00
    还是 SQLAlchemy 功能完善,即使只是拼 SQL ,比如
    sa.func.date(Model.c.created_at.op('AT TIME ZONE')(tz))

    一些较新的特性,比如 hstore 、 json 之类也是 SQLAlchemy 支持好
    Panmax
        42
    Panmax  
       2017-02-09 09:03:46 +08:00
    @chaleaoch 你好,想请教下 SqlAlchemy 的分表实现方法。

    我现在是用 automap_base 来反向映射的表结构。
    chaleaoch
        43
    chaleaoch  
       2017-02-09 09:24:48 +08:00
    @Panmax 我也不会,只是又一次参加 pycon 年会的时候 达达的 rest api 负责人在做分享的时候讲到过.
    你可以搜搜 2016 python 上海 网上能找到视频和 ppt 以及 github.
    findex
        44
    findex  
       2017-02-09 17:37:34 +08:00
    @bigzhu 我自己写了 ORM 后,觉得不如 SQLAlchemy 功能多,于是我就用 sqla 了。但是 sqla 比我自己写的 orm 臃肿。谁让它功能多呢?

    还有我要说说,很多游戏开发里面都用到了类似于 SQL ORM 的思想。什么 post connect, reconnect, 之类的都有。

    我觉得, ORM 在于思想问题。 django 自带的 ORM 跟 django 本身镶嵌太密切了,定制性能不好。当然如果你是 rich 的人,全上 django ,多花钱整机器也行。可以参考 instagram 。 sqla 的案例就更多了,什么 reddit , yelp 等等。

    要记得,优化好了的 ORM 总是不如优化好了的 SQL 纯净语句。我曾经为了这个动了些脑筋。
    findex
        45
    findex  
       2017-02-09 17:40:41 +08:00
    @est Python 就应该统一起来。驼峰风格学习下 Java 什么的语言。这样大家都能迅速读懂。
    可惜 python 的很多库写手,也许喝了瓶酒,写库的时候,命名非常不规范,反正发布了,能 work 就行。但是如果是大公司发布标准库的话,应该注意很多。
    当然当年的 MS 的很多库命名也十分令人蛋疼。
    est
        46
    est  
       2017-02-09 19:18:23 +08:00
    @findex 2333 其实质量比较差的是标准库。。
    wizardforcel
        47
    wizardforcel  
       2017-02-09 22:45:30 +08:00 via Android
    你们好像忽略了 java 上的 orm 。。基本都得手写 sql ,也就是查询结果能映射一下。

    优点是数据库特性支持的很好(废话),缺点是需要较高的 sql 功底。
    songdezu
        48
    songdezu  
       2017-02-14 00:25:59 +08:00
    我有个问题 大家看看对不对:
    用 orm 的主要优势是能保证各中平台 python Javascript 的语法一致性, 不用学习不同 lib 比如 pymongo mongoose 的不同 api
    param
        49
    param  
       2018-05-19 10:36:05 +08:00
    peewee 最大的问题在于没有好的 migration
    param
        50
    param  
       2018-05-19 10:37:20 +08:00
    @xiaket 我有一个项目就是单独使用 Django ORM
    param
        51
    param  
       2018-05-19 10:43:34 +08:00
    咦。。。发现自己一年多之前居然回复过这个帖。。
    xiaket
        52
    xiaket  
       2018-05-19 11:01:41 +08:00
    @param lol, 这算是自己挖自己的坟? txtx
    firejoke
        53
    firejoke  
       2018-07-05 15:37:49 +08:00
    @param 你好,有关于你的单独剥离 Django ORM 的相关笔记吗? (星星眼)~
    thinker3
        54
    thinker3  
       2018-09-15 09:26:49 +08:00
    @firejoke 我写过,settings.py 只需要 DATABASES、INSTALLED_APPS 等关键的定义就可以了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2856 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 23ms UTC 07:29 PVG 15:29 LAX 00:29 JFK 03:29
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86