দক্ষতার সাথে এসকিউএলএলএমি ওআরএম ব্যবহার করে ডাটাবেস আপডেট করা


116

আমি একটি নতুন অ্যাপ্লিকেশন শুরু করছি এবং একটি ওআরএম ব্যবহার করে দেখছি - বিশেষত এসকিউএলএলকেমি।

বলুন আমি আমার ডাটাবেসে একটি কলাম 'foo' পেয়েছি এবং আমি এটি বৃদ্ধি করতে চাই। সোজা স্ক্লাইটে, এটি সহজ:

db = sqlite3.connect('mydata.sqlitedb')
cur = db.cursor()
cur.execute('update table stuff set foo = foo + 1')

আমি এসকিউএএলএলকেমি এসকিউএল-বিল্ডার সমতুল্য খুঁজে পেয়েছি:

engine = sqlalchemy.create_engine('sqlite:///mydata.sqlitedb')
md = sqlalchemy.MetaData(engine)
table = sqlalchemy.Table('stuff', md, autoload=True)
upd = table.update(values={table.c.foo:table.c.foo+1})
engine.execute(upd)

এটি সামান্য ধীর, তবে এটিতে খুব বেশি কিছু নেই।

এসকিউএএলএলএমি ওআরএম পদ্ধতির জন্য এখানে আমার সেরা অনুমান:

# snip definition of Stuff class made using declarative_base
# snip creation of session object
for c in session.query(Stuff):
    c.foo = c.foo + 1
session.flush()
session.commit()

এটি সঠিক জিনিসটি করে, তবে এটি অন্য দুটি পদ্ধতির যতক্ষণ পঞ্চাশেরও বেশি সময় নেয়। আমার ধারণা এটি কারণ এটি সমস্ত ডেটা এটির সাথে কাজ করার আগে মেমোরিতে আনতে হবে।

এসকিউএএলএলচেমির ওআরএম ব্যবহার করে দক্ষ এসকিউএল উত্পন্ন করার কোনও উপায় আছে কি? বা অন্য কোনও অজগর ওআরএম ব্যবহার করছেন? অথবা আমি কি হাতে হাতে এসকিউএল লেখার পিছনে ফিরে যাই?


1
ঠিক আছে, আমি উত্তরটি ধরে নিচ্ছি "এটি ORMs ভাল করার মতো কিছু নয়"। আচ্ছা ভালো; আমি বেঁচে থাকি এবং শিখি।
জন ফুহি

বিভিন্ন ওআরএম এবং সেগুলি কীভাবে লোড এবং ডিউরেসের অধীনে সঞ্চালিত হয় সে সম্পর্কে কিছু পরীক্ষা-নিরীক্ষা হয়েছে। সহজ কোনও লিঙ্ক নেই, তবে পড়ার মতো।
ম্যাথু শিংকেল

শেষের (ওআরএম) উদাহরণ সহ অন্য একটি সমস্যাটি হ'ল এটি পারমাণবিক নয় ।
মেরিয়ান

উত্তর:


181

এসকিউএলএলচেমির ওআরএম বোঝানো হয় এটি এসকিউএল স্তরটির সাথে একসাথে ব্যবহার করা হয়, এটি আড়াল করে না। তবে একই লেনদেনে ওআরএম এবং সরল এসকিউএল ব্যবহার করার সময় আপনাকে একটি বা দুটি বিষয় মাথায় রাখতে হবে। মূলত, একপাশ থেকে, ORM ডেটা পরিবর্তনগুলি কেবলমাত্র যখন আপনি আপনার সেশন থেকে পরিবর্তনগুলি ফ্লাশ করবেন তখনই ডাটাবেসে হিট হবে। অন্য দিক থেকে, এসকিউএল ডেটা ম্যানিপুলেশন বিবৃতিগুলি আপনার সেশনে থাকা অবজেক্টগুলিকে প্রভাবিত করে না।

সুতরাং যদি আপনি বলেন

for c in session.query(Stuff).all():
    c.foo = c.foo+1
session.commit()

এটি যা বলে তা করবে, ডাটাবেস থেকে সমস্ত বস্তু আনুন, সমস্ত বস্তু সংশোধন করুন এবং তারপরে যখন ডাটাবেসে পরিবর্তনগুলি ফ্ল্যাশ করার সময় আসবে তখন একের পর এক সারিগুলি আপডেট করুন।

পরিবর্তে আপনার এটি করা উচিত:

session.execute(update(stuff_table, values={stuff_table.c.foo: stuff_table.c.foo + 1}))
session.commit()

এটি আপনার প্রত্যাশা অনুযায়ী একটি ক্যোয়ারী হিসাবে কার্যকর করা হবে এবং কমপক্ষে কমপক্ষে ডিফল্ট সেশন কনফিগারেশন সেশনটির সমস্ত ডেটা মেয়াদোত্তীর্ণ হওয়ার সময় প্রতিশ্রুতি দেওয়ার সময় আপনার কোনও বাসি ডেটা সমস্যা নেই।

প্রায় প্রকাশিত 0.5 টি সিরিজে আপনি আপডেট করার জন্য এই পদ্ধতিটি ব্যবহার করতে পারেন:

session.query(Stuff).update({Stuff.foo: Stuff.foo + 1})
session.commit()

এটি মূলত পূর্ববর্তী স্নিপেটের মতো একই এসকিউএল স্টেটমেন্টটি চালাবে, তবে পরিবর্তিত সারিগুলিও নির্বাচন করবে এবং সেশনে কোনও বাসি ডেটা সমাপ্ত হবে। আপনি যদি জানেন যে আপনি আপডেটের পরে কোনও সেশন ডেটা ব্যবহার করছেন না তবে synchronize_session=Falseআপনি আপডেটের বিবৃতিতে যুক্ত করতে পারেন এবং সেই নির্বাচনটি থেকে মুক্তি পাবেন।


2
তৃতীয় উপায়ে, এটি orm ইভেন্টটি (ট্রিপ আপ-এর মত) ট্রিগার করবে?
কেন

@ কেন, না, তা হবে না। কোয়েরি.আপডেট ডকস.সক্লাচেমি.আর.আর.এইং / ১৩ / সারমর্মার জন্য এপিআই ডক দেখুন । এর পরিবর্তে আপনার পরে_বুলক_আপডেট ডকস.সক্ল্যাচেমি.আর.এ.এন
১৩

91
session.query(Clients).filter(Clients.id == client_id_list).update({'status': status})
session.commit()

এটি চেষ্টা করুন =)


এই পদ্ধতিটি আমার পক্ষে কাজ করেছিল। তবে সমস্যাটি তার মন্থর। কয়েকটি 100 কে ডেটা রেকর্ডের জন্য এটির একটি ভাল সময় প্রয়োজন। আরও দ্রুত পদ্ধতি আছে কি?
বেরমেথিয়াস

এই পদ্ধতির আমার জন্য অনেক ধন্যবাদ কাজ। এটি সত্যই খারাপ যে স্ক্লাচেমির কাছে jsonকলামটি আপডেট করার সংক্ষিপ্ত উপায় নেই
জয় প্রকাশ

6
এই পদ্ধতিটি ব্যবহার করার পরেও পারফরম্যান্স সংক্রান্ত সমস্যাগুলির ক্ষেত্রে: ডিফল্টরূপে এটি প্রথমে প্রতিটি রেকর্ডের জন্য একটি নির্বাচন করতে পারে এবং পরে কেবল আপডেট হবে DATE সিঙ্ক্রোনাইজ_অ্যাসিশন = আপডেট () পদ্ধতিতে মিথ্যা হওয়া এটি ঘটতে বাধা দেয় তবে কমিট () এর পূর্বে আপনি পুনরায় আপডেট হওয়া অবজেক্টগুলি ব্যবহার না করলে কেবল এটিই নিশ্চিত করুন।
teuneboon

25

স্কেলচেমি ব্যবহার করে আপডেট করার বিভিন্ন উপায় রয়েছে

1) for c in session.query(Stuff).all():
       c.foo += 1
   session.commit()

2) session.query().\
       update({"foo": (Stuff.foo + 1)})
   session.commit()

3) conn = engine.connect()
   stmt = Stuff.update().\
       values(Stuff.foo = (Stuff.foo + 1))
   conn.execute(stmt)

6

ক্ষেত্রগুলিকে ম্যানুয়ালি না করে কীভাবে একই সমস্যার সমাধান করবেন তার একটি উদাহরণ এখানে:

from sqlalchemy import Column, ForeignKey, Integer, String, Date, DateTime, text, create_engine
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm.attributes import InstrumentedAttribute

engine = create_engine('postgres://postgres@localhost:5432/database')
session = sessionmaker()
session.configure(bind=engine)

Base = declarative_base()


class Media(Base):
  __tablename__ = 'media'
  id = Column(Integer, primary_key=True)
  title = Column(String, nullable=False)
  slug = Column(String, nullable=False)
  type = Column(String, nullable=False)

  def update(self):
    s = session()
    mapped_values = {}
    for item in Media.__dict__.iteritems():
      field_name = item[0]
      field_type = item[1]
      is_column = isinstance(field_type, InstrumentedAttribute)
      if is_column:
        mapped_values[field_name] = getattr(self, field_name)

    s.query(Media).filter(Media.id == self.id).update(mapped_values)
    s.commit()

সুতরাং একটি মিডিয়া উদাহরণ আপডেট করতে, আপনি এই জাতীয় কিছু করতে পারেন:

media = Media(id=123, title="Titular Line", slug="titular-line", type="movie")
media.update()

1

পর্যাপ্ত পরীক্ষার পরে, আমি চেষ্টা করব:

for c in session.query(Stuff).all():
     c.foo = c.foo+1
session.commit()

(আইআইআরসি, কমিট () ফ্লাশ () ছাড়াই কাজ করে।

আমি খুঁজে পেয়েছি যে অনেক সময় একটি বড় প্রশ্ন করা এবং তারপরে অজগরটিতে পুনরাবৃত্তি করা অনেকগুলি প্রশ্নের চেয়ে দ্রুততর 2 অর্ডার বাড়ানো যেতে পারে। আমি ধরে নিয়েছি যে ক্যোয়ারী অবজেক্টের সমস্ত () পদ্ধতি দ্বারা উত্পন্ন কোনও তালিকার উপরে পুনরাবৃত্তির চেয়ে ক্যোয়ারী অবজেক্টের উপর পুনরাবৃত্তি কম দক্ষ।

[দয়া করে নীচের মন্তব্যটি নোট করুন - এটি কিছুতেই গতি বাড়ায় না]।


2
.All () যুক্ত করা এবং .ফ্লুশ () অপসারণ সময়টি মোটেও পরিবর্তন করে নি।
জন ফুহি

1

যদি এটি বস্তু তৈরির ক্ষেত্রে ওভারহেডের কারণে হয়, তবে সম্ভবত এটি SA এর সাথে মোটেও বাড়ানো যায় না।

যদি এটি সম্পর্কিত বিষয়গুলি লোড করা হয় কারণ এটি হয় তবে আপনি অলস লোড দিয়ে কিছু করতে সক্ষম হতে পারেন। রেফারেন্সের কারণে প্রচুর অবজেক্ট তৈরি হচ্ছে? (IE, কোনও কোম্পানির অবজেক্ট প্রাপ্তি সম্পর্কিত সমস্ত লোকের বস্তুও পায়)।


নাহ, টেবিলের সব কিছু নিজস্ব। আমি এর আগে কখনও কোনও ওআরএম ব্যবহার করি নি - এটাই কি তারা খারাপ হয়?
জন ফুহি

1
অবজেক্ট তৈরি করার কারণে সেখানে একটি ওভারহেড রয়েছে, তবে আমার মতে এটি দন্ডের পক্ষে মূল্যবান - অবিচ্ছিন্নভাবে একটি ডাটাবেসে অবজেক্টগুলি সঞ্চয় করতে সক্ষম হওয়া দুর্দান্ত।
ম্যাথু শিংকেল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.