রেলগুলিতে একক কলে একাধিক বস্তু সংরক্ষণ করা


94

আমার রেলপথে একটি পদ্ধতি রয়েছে যা এই জাতীয় কিছু করছে:

a = Foo.new("bar")
a.save

b = Foo.new("baz")
b.save

...
x = Foo.new("123", :parent_id => a.id)
x.save

...
z = Foo.new("zxy", :parent_id => b.id)
z.save

সমস্যাটি হ'ল এটি আমার যুক্ত হওয়া আরও সত্তা এবং আরও বেশি সময় নেয়। আমি সন্দেহ করি এটি কারণ এটি প্রতিটি রেকর্ডের জন্য ডাটাবেস হিট করতে হবে। যেহেতু তারা বাসা বেঁধেছে তাই আমি জানি যে বাবা-মা বাঁচার আগে আমি বাচ্চাদের বাঁচাতে পারি না, তবে আমি একবারে এবং তারপরে সমস্ত বাচ্চাকে বাঁচাতে চাই। ভালো কিছু হবে যেমন:

a = Foo.new("bar")
b = Foo.new("baz")
...
saveall(a,b,...)

x = Foo.new("123", :parent_id => a.id)
...
z = Foo.new("zxy", :parent_id => b.id)
saveall(x,...,z)

এটি কেবলমাত্র দুটি ডাটাবেস হিটগুলিতেই করা হবে। রেলপথে এটি করার কোনও সহজ উপায় আছে, বা আমি একবারে এটি করে আটকাচ্ছি?

উত্তর:


69

আপনি Foo.new এর পরিবর্তে Foo.create ব্যবহার করার চেষ্টা করতে পারেন। তৈরি করুন "একটি বস্তু (বা একাধিক বস্তু) তৈরি করে এবং বৈধতাগুলি পাস হলে এটি ডাটাবেসে সংরক্ষণ করে The

আপনি এই জাতীয় একাধিক বস্তু তৈরি করতে পারেন:

# Create an Array of new objects
  parents = Foo.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }])

তারপরে, প্রতিটি পিতামাতার জন্য, আপনি এর সংযুক্তিতে যুক্ত করতে ক্রিয়েটও ব্যবহার করতে পারেন:

parents.each do |parent|
  parent.children.create (:child_name => 'abc')
end

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


78
দুর্ভাগ্যক্রমে, অ্যাক্টিভেকর্ড প্রতিটি তৈরি মডেল অনুসারে একটি ইনসার্ট ক্যোয়ারী উত্পন্ন করবে। ওপি একটি একক INSERT কল চায়, যা অ্যাক্টিভেকর্ড করবে না।
ফ্রান্সোয়েস বিউসোলিল

হ্যাঁ, আমি এটি একটি sertোকানো কলটিতে সব পাওয়ার আশা করছিলাম, তবে যদি অ্যাক্টিভের্কর্ডটি স্মার্ট না হয় তবে আমার ধারণা এটি খুব সহজ নয়।
ক্যাপচার্যাগ

@ ফ্রানসোইসবিউসোলিল আপনার মনে প্রশ্ন স্ট্যাকওভারফ্লো.com / প্রশ্নগুলি / 15386450 /… দেখে মনে হবে, আমি কেন একই সময়ে একাধিক রেকর্ড সন্নিবেশ করতে পারি না?
রিচলেউইস

4
এটি সত্য যে আপনি ActiveRecord::Base.transaction { records.each(&:save) }এআরএসটি একটি ইনসার্ট বা আপডেট আপডেট করতে পারবেন না, তবে এর সাথে বা অনুরূপ আপনি কমপক্ষে সমস্ত INSERTs বা আপডেটগুলি একটি লেনদেনে রাখতে পারেন।
ইয়ুভাল

4
প্রকৃতপক্ষে, ওপি ডাটাবেসটিকে কম হিট করতে চায়, ডিবি অ্যাক্সেসকে ত্বরান্বিত করতে চায় এবং অ্যাক্টিভেকর্ডটি আসলে আপনাকে একটি ট্রানজেকশনে সমস্ত কলকে ব্যাচ করে তা করতে দেয়। (হরিশের উত্তর দেখুন, যা গ্রহণযোগ্য উত্তর হওয়া উচিত)) অ্যাক্টিভেকর্ড আপনাকে যা করতে দেবে না তা হ'ল ডিবিই প্রতিটি লেনদেনের জন্য একটি INSERT ক্যোয়ারী তৈরি করতে পারে, তবে এটি এতটা গুরুত্বপূর্ণ নয়, যেহেতু বিলম্বতা নেটওয়ার্কটি করে আসে ডিবিতে অ্যাক্সেস করুন, এবং ডিএনএসের ভিতরে নয় যখন এটি ইনসার্ট অনুসন্ধান করে।
ম্যাগনে

100

যেহেতু আপনাকে একাধিক সন্নিবেশ করানো দরকার, তাই ডাটাবেস একাধিকবার হিট হবে। আপনার ক্ষেত্রে বিলম্ব হওয়ায় প্রতিটি সঞ্চয় বিভিন্ন ডিবি লেনদেনে হয়। আপনার সমস্ত ক্রিয়াকলাপকে একটি লেনদেনে সংযুক্ত করে আপনি বিলম্বকে হ্রাস করতে পারেন।

class Foo
  belongs_to  :parent,   :class_name => "Foo"
  has_many    :children, :class_name => "Foo", :foreign_key=> "parent_id"
end

আপনার সংরক্ষণের পদ্ধতিটি দেখতে দেখতে এটির মতো হতে পারে:

# build the parent and the children
a = Foo.new(:name => "bar")
a.children.build(:name => "123")

b = Foo.new("baz")
b.children.build(:name => "zxy")

#save parents and their children in one transaction
Foo.transaction do
  a.save!
  b.save!
end

saveপিতা বা মাতা বস্তুর উপর কল শিশু বস্তু সংরক্ষণ করে।


4
শুধু আমি যা খুঁজছিলাম। আমার বীজ প্রচুর গতি বাড়ায়। ধন্যবাদ :-)
রেনরা

17

insert_all (রেল 6+)

Rails 6একটি নতুন পদ্ধতি insert_all প্রবর্তন করেছে , যা একক SQL INSERTবিবৃতিতে ডাটাবেসে একাধিক রেকর্ড সন্নিবেশ করে ।

এছাড়াও, এই পদ্ধতিটি কোনও মডেলকে ইনস্ট্যান্ট করে না এবং অ্যাক্টিভ রেকর্ড কলব্যাকস বা বৈধতাগুলিকে কল করে না।

সুতরাং,

Foo.insert_all([
  { first_name: 'Jamie' },
  { first_name: 'Jeremy' }
])

এটা তুলনায় উল্লেখযোগ্যভাবে আরও দক্ষ

Foo.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }])

আপনি যা করতে চান তা হ'ল নতুন রেকর্ড সন্নিবেশ করানো।


4
আমরা আমাদের অ্যাপটি আপডেট না করা পর্যন্ত অপেক্ষা করতে পারি না। রেল in এ অনেক দুর্দান্ত জিনিস
ড্যান

4
নোটটিতে এক জিনিস: insert_all শিরোণামে callbacks & যাচাই অগ্রাহ্য: edgeguides.rubyonrails.org/...
sujay

11

অন্য কোথাও পাওয়া দুটি উত্তরগুলির মধ্যে একটি: বিয়ারলিংটন দ্বারা । পারফরম্যান্সের জন্য দু'টিই আপনার সেরা বাজি


আমি মনে করি আপনার সেরা বাজি পারফরম্যান্স-অনুসারে এসকিউএল ব্যবহার করা হবে এবং কোয়েরিতে একাধিক সারি সন্নিবেশ করানো হবে। আপনি যদি কোনও INSERT বিবৃতি তৈরি করতে পারেন যা এর মতো কিছু করে:

অন্তর্ভুক্ত foos_bars (foo_id, বার_আইডি) ভ্যালু (1,1), (1,2), (1,3) .... আপনার একক ক্যোয়ারিতে হাজার হাজার সারি সন্নিবেশ করতে সক্ষম হওয়া উচিত। আমি আপনার ভর_হাবত্ম পদ্ধতিটি চেষ্টা করি নি, তবে মনে হয় আপনি যেমন কিছু করতে পেরেছিলেন:


bars = Bar.find_all_by_some_attribute(:a) 
foo = Foo.create
values = bars.map {|bar| "(#{foo.id},#{bar.id})"}.join(",") 
connection.execute("INSERT INTO foos_bars (foo_id, bar_id) VALUES
#{values}")

এছাড়াও, যদি আপনি "কিছু_অ্যাট্রিবিউট" দ্বারা বারটি অনুসন্ধান করেন, আপনার ডেটাবেজে সেই ক্ষেত্রটি সূচিকৃত হয়েছে তা নিশ্চিত করুন।


বা

আপনার এখনও অ্যাক্টিভরেকর্ড-আমদানিতে এক নজর থাকতে পারে। এটি ঠিক যে এটি কোনও মডেল ছাড়া কাজ করে না, তবে আপনি কেবল আমদানির জন্য একটি মডেল তৈরি করতে পারেন।


FooBar.import [:foo_id, :bar_id], [[1,2], [1,3]]

চিয়ার্স


এটি সন্নিবেশ করানোর জন্য দুর্দান্ত কাজ করে তবে এক লেনদেনে একাধিক রেকর্ড আপডেট করার জন্য কী?
অবিশাই

4
আপডেট করার জন্য আপনার ব্যবহার উপস্থাপন করা উচিত: github.com/seamusabshere/upsert । চিয়ার্স
Nguyen Chien কংগ্রেস

বর্গ কোয়েরি সহ খুব খারাপ ধারণা। আপনার অ্যাক্টিভেকর্ড এবং লেনদেন ব্যবহার করা উচিত।
কেরোজু

এটি কোনও খারাপ ধারণা নয়। আমার ধারণা, আপনি যদি একটি সন্নিবেশ করান তবে তা সফল বা ব্যর্থ হবে, লেনদেনের প্রয়োজন হবে না, আমার ধারণা। অথবা আপনি সর্বদা লেনদেনের ব্লকে ONEোকাতে পারেন।
ফার্নান্দো ফ্যাব্রেতি

এটি খারাপ রেলের অনুশীলন
ব্লেয়ার অ্যান্ডারসন

0

আপনার এই রত্নটি "ফাস্টআইনেসার" ব্যবহার করতে হবে -> https://github.com/joinhandshake/fast_inserter

এবং একটি বিশাল সংখ্যা এবং হাজার হাজার রেকর্ড সন্নিবেশ করা দ্রুত কারণ এই রত্নটি সক্রিয় রেকর্ডকে এড়িয়ে চলে এবং কেবল একটি একক স্কেল কাঁচা কোয়েরি ব্যবহার করে


4
যদিও রত্নটির লিঙ্কটি কার্যকর হতে পারে তবে দয়া করে এমন কিছু কোড সরবরাহ করুন যা প্রশ্নকারী তাদের বর্তমান কোডের পরিবর্তে ব্যবহার করতে পারে (প্রশ্ন দেখুন)।
ট্রিনকোট


4
উত্তরের প্রয়োজনীয় তথ্য এম্বেড থাকা দরকার । দয়া করে আপনার উত্তরটি সম্পাদনা করুন এবং সেখানে লিঙ্কটি যুক্ত করুন, এবং উত্তরের ভিতরে এর প্রয়োজনীয় অংশগুলিও যুক্ত করুন, যাতে এটি স্বয়ংসম্পূর্ণ থাকে।
ট্রিনকোট

-2

দ্রুত এবং কেবল একবার ডিবি হিট করার জন্য আপনার কোনও রত্নের দরকার নেই!

জ্যাকর্গ আমাদের জন্য এটি কাজ করেছে: https://gist.github.com/jackrg/76ade1724bd816292e4e


মঙ্গোদবের পক্ষে এর মতো কোনও সমাধান?
ব্রেনো
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.