yamakiy’s tech blog

技術系の記事をメインにやります。

DB操作でORMを使うことの是非について

qiitaでこんな記事があったのでちょっと考えてみる

qiita.com

ORMのメリット

  • 動的にwhere句を簡単に安全にかける
  • 可読性が高い(保守しやすい)
  • PostgreSQLMySQLが混在するような環境でも同じ書き方ができる

ORMのデメリット

  • 最適化する時にはやはり生の方が便利
  • 生クエリーを知らなくてもかけるため、技術的な知識が身に付きにくい
  • 生クエリーでないと実現できない場合がある

少し比較

単純なクエリー

orm 有り(django)

shops = Shops.objects.filter()

orm 無し(MySQL-pythonライブラリ使用)

sql = 'SELECT * FROM shops'
cursor.execute(sql)
cursor.fetchall()

これはそれほど変わらない

動的にwhere句を生成する時

例えば、idとkeywordによって検索条件を指定してリストを出力する時
idは一致検索、keywordは含むかどうかで判定する

orm 有り(django)

shops = Shops.objects.filter()
if "id" in requests.GET:
    shops.filter(id=requests.GET["id"])
if "keyword" in requests.GET:
    shops.filter(keyword__in=requests.GET["keyword"])

orm 無し(MySQL-pythonライブラリ使用)

sql = 'SELECT * FROM shops'
wheres = []
sql_args = []
if "id" in requests.GET:
    wheres.append('id = "%s"')
    sql_args.append(requests.GET["id"])
if "keyword" in requests.GET:
    wheres.append('keyword LIKE "%s"')
    sql_args.append(requests.GET["keyword"])

sql += " WHERE "+" and ".join(wheres) if len(wheres) > 1 else ""
cursor.execute(sql, sql_args)
cursor.fetchall()

この例だと動的生成はORM利用の方がしやすいと思う
ただ、自分たちで動的に生成しやすいようなclassを作って管理するとか方法はあるかもしれない

速度が問題となるケースは生クエリー

例えばslowqueryが出てる時に手動でチューニングする場合
joinの順番やorderの仕方などをqueryを視覚的に認知しながら組める点は生query有利

また、ormはループしながら単発のqueryを叩いているときがあるなど、非効率な動きをしてることがある
こんな時、生ならquery一発でもってきて後から精査できる

また、サブクエリー等を含んだ複雑な条件式もORMで組むより生の方が見やすく、書きやすいことも多い

最後に

個人的には共存していけばいいじゃないの と思う
それぞれ得手不得手があるのだから、全部ORMとか生にこだわる必要はないと思う

自分はほぼORMで速度上の問題がある時や、複雑なクエリーを汲む時だけ生でやってます