জেপিএ: বড় ফলাফলের সেটগুলিতে পুনরাবৃত্তি করার সঠিক প্যাটার্নটি কী?


114

ধরা যাক আমার কয়েক মিলিয়ন সারি সহ একটি টেবিল রয়েছে। জেপিএ ব্যবহার করে, সেই টেবিলের বিপরীতে কোন প্রশ্নের পুনরাবৃত্তি করার সঠিক উপায়টি কী, যেমন লক্ষ লক্ষ বস্তুর সাথে আমার সমস্ত মেমরির অন্তর্ভুক্ত নেই ?

উদাহরণস্বরূপ, আমি সন্দেহ করি যে টেবিলটি বড় হলে নিম্নলিখিতগুলি ফুরিয়ে যাবে:

List<Model> models = entityManager().createQuery("from Model m", Model.class).getResultList();

for (Model model : models)
{
     System.out.println(model.getId());
}

পৃষ্ঠাবদ্ধকরণ (লুপিং এবং ম্যানুয়ালি আপডেট করা setFirstResult()/ setMaxResult()) কি আসলেই সেরা সমাধান?

সম্পাদনা করুন : আমি যে প্রাথমিক ব্যবহার-কে লক্ষ্য করছি তা এক ধরণের ব্যাচের কাজ atch দৌড়াতে যদি দীর্ঘ সময় লাগে তবে এটি ঠিক আছে। কোনও ওয়েব ক্লায়েন্ট জড়িত নেই; আমার প্রতিটি সারির জন্য একবারে "কিছু করতে" দরকার, এক সাথে একবারে (বা কিছু ছোট এন)। আমি কেবল একই সময়ে সমস্তগুলিকে স্মৃতিতে না এড়াতে চেষ্টা করছি।


আপনি কোন ডাটাবেস এবং জেডিবিসি ড্রাইভার ব্যবহার করছেন?

উত্তর:


55

হাইবারনেট সহ জাভা পার্সিস্টির পৃষ্ঠা 537 ব্যবহার করে একটি সমাধান দেয় ScrollableResults, তবে হায় হায় এটি কেবল হাইবারনেটের পক্ষে।

সুতরাং দেখে মনে হচ্ছে যে setFirstResult/ setMaxResultsএবং ম্যানুয়াল পুনরাবৃত্তিটি ব্যবহার করা সত্যই প্রয়োজনীয়। জেপিএ ব্যবহার করে আমার সমাধানটি এখানে:

private List<Model> getAllModelsIterable(int offset, int max)
{
    return entityManager.createQuery("from Model m", Model.class).setFirstResult(offset).setMaxResults(max).getResultList();
}

তারপরে, এটি এর মতো ব্যবহার করুন:

private void iterateAll()
{
    int offset = 0;

    List<Model> models;
    while ((models = Model.getAllModelsIterable(offset, 100)).size() > 0)
    {
        entityManager.getTransaction().begin();
        for (Model model : models)
        {
            log.info("do something with model: " + model.getId());
        }

        entityManager.flush();
        entityManager.clear();
        em.getTransaction().commit();
        offset += models.size();
    }
}

33
আমি মনে করি ব্যাচ প্রক্রিয়া চলাকালীন নতুন সন্নিবেশ থাকলে উদাহরণটি নিরাপদ নয়। ব্যবহারকারীর অবশ্যই একটি কলামের ভিত্তিতে অর্ডার করতে হবে যেখানে এটি নিশ্চিত যে সদ্য সন্নিবেশ করা ডেটা ফলাফল তালিকার শেষে থাকবে।
বালাজস জোসল্ডোস

যখন বর্তমান পৃষ্ঠাটি সর্বশেষ পৃষ্ঠা এবং তার size() == 100পরিবর্তে 100 টিরও কম উপাদান রয়েছে যাচাই করা খালি তালিকা ফেরত দেওয়ার জন্য একটি অতিরিক্ত ক্যোয়ারি এড়িয়ে যাবে
সিডালেক্সেন্ডার

38

আমি এখানে উপস্থাপিত উত্তরগুলি চেষ্টা করেছি, তবে জবস 5.1 + মাইএসকিউএল সংযোগকারী / জে 5.1.15 + হাইবারনেট 3.3.2 সেগুলির সাথে কাজ করে নি। আমরা সবে JBoss 4.x থেকে JBoss 5.1 এ স্থানান্তরিত করেছি, তাই আমরা আপাতত এটির সাথে আটকে গিয়েছি, এবং এইভাবে আমরা সর্বশেষতম হাইবারনেটটি ব্যবহার করতে পারি 3.3.2।

বেশ কয়েকটি অতিরিক্ত পরামিতি যুক্ত করা কাজটি করেছে এবং এর মতো কোড ওমস ছাড়াই চলে:

        StatelessSession session = ((Session) entityManager.getDelegate()).getSessionFactory().openStatelessSession();

        Query query = session
                .createQuery("SELECT a FROM Address a WHERE .... ORDER BY a.id");
        query.setFetchSize(Integer.valueOf(1000));
        query.setReadOnly(true);
        query.setLockMode("a", LockMode.NONE);
        ScrollableResults results = query.scroll(ScrollMode.FORWARD_ONLY);
        while (results.next()) {
            Address addr = (Address) results.get(0);
            // Do stuff
        }
        results.close();
        session.close();

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


2
হাই জেডএস, আপনার কয়েক মিলিয়ন সারি স্ক্যান করার ব্যবহার অবশ্যই আমার পক্ষে সাধারণ এবং চূড়ান্ত কোড পোস্ট করার জন্য আপনাকে ধন্যবাদ। আমার ক্ষেত্রে আমি রেকর্ডগুলি সলারের সাথে সরিয়ে দিচ্ছি, পুরো পাঠ্য সন্ধানের জন্য তাদের সূচী করতে। এবং, ব্যবসায়ের নিয়মের কারণে আমি won'tুকব না, আমাকে জাইবিবিসি বা সোলারের অন্তর্নির্মিত মডিউলগুলি ব্যবহার করে হাইবারনেট, বনাম যেতে হবে go
মার্ক বনেট

সাহায্য করতে পারলে খুশি :-). আমরা বৃহত্তর ডেটা সেটগুলির সাথেও কাজ করছি, এক্ষেত্রে ব্যবহারকারীকে একই শহর / কাউন্টি, বা কখনও কখনও এমনকি রাজ্যের সমস্ত রাস্তার নামগুলিও জিজ্ঞাসা করতে দেয়, তাই সূচকগুলি তৈরি করতে প্রচুর ডেটা পড়া প্রয়োজন।
জিডিএস

মাইএসকিউএল সঙ্গে প্রদর্শিত হবে আপনি কি সত্যিই ঐ সমস্ত হুপ্স মধ্য দিয়ে যেতে না: stackoverflow.com/a/20900045/32453 (অন্যান্য গোয়েন্দা পুলিশের কম কঠোর আমি মনে করেছিলাম ... হতে পারে)
rogerdpack

32

আপনি সরাসরি জেপিএতে সত্যই এটি করতে পারবেন না, তবে হাইবারনেটের স্টেটলেস সেশন এবং স্ক্রোলযোগ্য ফলাফল সেটগুলির পক্ষে সমর্থন রয়েছে।

আমরা এর সাহায্যে নিয়মিতভাবে কয়েক বিলিয়ন সারি প্রক্রিয়াজাত করি ।

ডকুমেন্টেশনের লিঙ্কটি এখানে: http://docs.jboss.org/hibernate/core/3.3/references/en/html/batch.html#batch-statelesssession


17
ধন্যবাদ। হাইবারনেটের মাধ্যমে কেউ কয়েক বিলিয়ন সারি করছে তা জেনে রাখা ভাল। এখানে কিছু লোক দাবি করছেন এটি অসম্ভব। :-)
জর্জ আর্মহোল্ড

2
এখানেও উদাহরণ যুক্ত করা সম্ভব? আমি ধরে নিলাম এটি জেডএসসের উদাহরণের সাথে মিল?
রজারডপ্যাক 21

19

সত্যি কথা বলতে, আমি জেপিএ ছেড়ে জেডিবিসি (তবে অবশ্যই JdbcTemplateসমর্থন ক্লাস বা এ জাতীয় পছন্দ ব্যবহার করে ) এর সাথে লেগে থাকার পরামর্শ দেব । জেপিএ (এবং অন্যান্য ওআরএম সরবরাহকারী / স্পেসিফিকেশন) এক লেনদেনের মধ্যে অনেকগুলি বস্তুর উপর পরিচালনা করার জন্য ডিজাইন করা হয়নি কারণ তারা ধরে নেয় যে লোড হওয়া সমস্ত কিছুই প্রথম স্তরের ক্যাশে থাকা উচিত (সুতরাং clear()জেপিএতে প্রয়োজনীয়তা )।

এছাড়াও আমি আরও নিম্ন স্তরের সমাধানের পরামর্শ দিচ্ছি কারণ ওআরএমের ওভারহেড (প্রতিফলনটি একটি আইসবার্গের কেবলমাত্র একটি টিপ) এত তাৎপর্যপূর্ণ হতে পারে, যে সমতলটির উপরে পুনরাবৃত্তি হতে পারে ResultSet, এমনকি উল্লিখিত মতো কিছু হালকা ওজনের সমর্থন ব্যবহার JdbcTemplateকরা আরও দ্রুত হবে।

জেপিএ কেবলমাত্র প্রচুর সংখ্যক সত্তার অপারেশন করার জন্য ডিজাইন করা হয়নি। আপনি এড়াতে flush()/ খেলতে clear()পারেন OutOfMemoryError, তবে এটি আবার একবার বিবেচনা করুন। আপনি বিশাল সংস্থান ব্যবহারের দাম খুব কম প্রদান করতে পারেন gain


জেপিএর সুবিধাটি হ'ল কেবল ডাটাবেস অজ্ঞোস্টিক নয় বরং aতিহ্যবাহী ডাটাবেস (নোএসকিউএল) ব্যবহার না করার সম্ভাবনাও রয়েছে। এখন থেকে এবং তারপর এবং সাধারণত ব্যাচের ক্রিয়াকলাপ খুব কমই করা হয় ফ্লাশ / সাফ করা কঠিন নয়।
অ্যাডাম জেন্ট

1
হাই থমাসজ আমার কাছে জেপিএ / হাইবারনেট সম্পর্কে অভিযোগ করার প্রচুর কারণ রয়েছে, তবে শ্রদ্ধার সাথে আমি সত্যিই সন্দেহ করি যে তারা "অনেকগুলি বিষয় চালনার জন্য ডিজাইন করা হয়নি"। আমার সন্দেহ হয় যে আমাকে এই ব্যবহারের ক্ষেত্রে সঠিক প্যাটার্ন শিখতে হবে।
জর্জ আর্মহোল্ড

4
ঠিক আছে, আমি কেবল দুটি প্যাটার্ন সম্পর্কে ভাবতে পারি: পৃষ্ঠাগুলি (বেশ কয়েকবার উল্লিখিত) এবং flush()/ clear()। প্রথমটি হ'ল আইএমএইচও, যা ব্যাচ প্রসেসিংয়ের উদ্দেশ্যে তৈরি করা হয়নি, যখন ফ্লাশ () / ক্লিয়ার () এর ক্রম ব্যবহার করে ফাঁস বিমূর্তের মতো গন্ধ হয় ।
টমাসজ নুরকিউইচ

হ্যাঁ, এটি পৃষ্ঠাগুলি এবং ফ্লাশ / ক্লিয়ারের সংমিশ্রণ ছিল যা আপনি উল্লেখ করেছেন। ধন্যবাদ!
জর্জ আর্মহোল্ড

7

আপনি যদি EclipseLink I ব্যবহার করেন তবে এই পদ্ধতিটি ব্যবহারের জন্য Iteable হিসাবে ফলাফল পেতে পারেন

private static <T> Iterable<T> getResult(TypedQuery<T> query)
{
  //eclipseLink
  if(query instanceof JpaQuery) {
    JpaQuery<T> jQuery = (JpaQuery<T>) query;
    jQuery.setHint(QueryHints.RESULT_SET_TYPE, ResultSetType.ForwardOnly)
       .setHint(QueryHints.SCROLLABLE_CURSOR, true);

    final Cursor cursor = jQuery.getResultCursor();
    return new Iterable<T>()
    {     
      @SuppressWarnings("unchecked")
      @Override
      public Iterator<T> iterator()
      {
        return cursor;
      }
    }; 
   }
  return query.getResultList();  
}  

বন্ধ পদ্ধতি

static void closeCursor(Iterable<?> list)
{
  if (list.iterator() instanceof Cursor)
    {
      ((Cursor) list.iterator()).close();
    }
}

6
চমৎকার jQuery অবজেক্ট
usr-স্থানীয়-ΕΨΗΕΛΩΝ

আমি আপনার কোডটি চেষ্টা করেছিলাম তবে এখনও ওওএম পাই - এটি সমস্ত টি অবজেক্ট (এবং টি থেকে উল্লিখিত সমস্ত টেবিল অবজেক্ট) কখনই জিসি হয় না। প্রোফাইলিং তাদের org.eclipse.persistance.intern.sessions.RepeatableWriteUnitOfWork এর সাথে org.eclipse.persistance.intern.identitymaps.CacheKey এ "টেবিল" থেকে উল্লেখ করা হয়েছে তা দেখায় Prof আমি ক্যাশে সন্ধান করেছি এবং আমার সেটিংস সমস্ত ডিফল্ট (নির্বাচনযোগ্য অক্ষম করুন, সফট সাবকাশে সহ দুর্বল, ক্যাশে আকার 100, ড্রপ অবৈধ)। আমি অক্ষমকরণ সেশনগুলি সন্ধান করব এবং এটি সাহায্য করে কিনা তা দেখুন। বিটিডাব্লু আমি কেবল "ফর (টি ও: ফলাফল)" ব্যবহার করে রিটার্ন কার্সার দিয়ে পুনরাবৃত্তি করি।
এডি বাইস

Badum tssssssss
dctremblay

5

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

আপনি যদি ক্লায়েন্টের কাছে এক মিলিয়ন রেকর্ড প্রদর্শন করতে চলেছেন তবে দয়া করে আপনার ব্যবহারকারী ইন্টারফেসটি পুনর্বিবেচনা করুন। এই ক্ষেত্রে, উপযুক্ত সমাধানটি আপনার ফলাফলগুলি পৃষ্ঠাভুক্ত করছে এবং ব্যবহার করছে setFirstResult()এবং setMaxResult()

আপনি যদি প্রচুর পরিমাণে রেকর্ডের আপডেট চালু করে থাকেন তবে আপনি আপডেটটি আরও সহজ এবং ব্যবহারে রাখবেন Query.executeUpdate()। Ptionচ্ছিকভাবে, আপনি বার্তা-চালিত বিন ও ওয়ার্ক ম্যানেজার ব্যবহার করে অ্যাসিক্রোনাস মোডে আপডেটটি সম্পাদন করতে পারেন।

যদি আপনি পুনরুদ্ধারকৃত সত্তাগুলির উপর কিছু পরিসংখ্যান গণনা করে থাকেন তবে আপনি জেপিএ স্পেসিফিকেশন দ্বারা সংজ্ঞায়িত গ্রুপিং ফাংশনগুলিতে সুবিধা নিতে পারেন।

অন্য যে কোনও ক্ষেত্রে, দয়া করে আরও নির্দিষ্ট করুন :)


বেশ সহজভাবে, আমার "প্রতিটি" জন্য সারিতে কিছু করা দরকার। অবশ্যই এটি সাধারণ ব্যবহারের ক্ষেত্রে। আমি বর্তমানে যে নির্দিষ্ট ক্ষেত্রে কাজ করছি, আমার প্রতিটি সারি থেকে একটি আইডি (পিকে) ব্যবহার করে আমার ডাটাবেসের বাইরে সম্পূর্ণ বাহ্যিক ওয়েব পরিষেবা সম্পর্কে জিজ্ঞাসা করা দরকার। ফলাফলগুলি কোনও ক্লায়েন্ট ওয়েব ব্রাউজারে ফিরে প্রদর্শিত হয় না, তাই এর কথা বলার মতো কোনও ব্যবহারকারী ইন্টারফেস নেই। এটি একটি ব্যাচের কাজ, অন্য কথায়।
জর্জ আর্মহোল্ড

আপনার যদি প্রতিটি সারির জন্য প্রিন্ট আইডি "প্রয়োজন" হয় তবে প্রতিটি সারি পাওয়ার মতো আর কোনও উপায় নেই, আইডি এবং মুদ্রণ পান। আপনার কী করা উচিত তার উপর সেরা সমাধান নির্ভর করে।
ডাইনিয়াস

@ ক্যাফিন কোমা, যদি আপনার কেবল প্রতিটি সারির আইডি প্রয়োজন হয় তবে সম্ভবত সবচেয়ে বড় উন্নতিটি কেবলমাত্র সেই কলামটি আনতে হবে, SELECT m.id FROM Model mএবং তারপরে একটি তালিকা <ইন্টিজার> এর মাধ্যমে পুনরাবৃত্তি হতে পারে।
জর্ন হোর্স্টম্যান

1
@ জার্ন হোর্স্টম্যান- যদি কয়েক মিলিয়ন সারি থাকে তবে তা কি সত্যই গুরুত্ব পাবে? আমার বক্তব্যটি হল লক্ষ লক্ষ বস্তু (তবে ছোট) সহ একটি অ্যারেলিস্ট জেভিএম হিপটির পক্ষে ভাল হতে পারে না।
জর্জ আর্মহোল্ড

@ ডেনিয়াস: আমার প্রশ্নটি সত্যই: "আমি কীভাবে প্রতিটি সারিতে পুনরাবৃত্তি করতে পারি, পুরো অ্যারেলিস্টটি স্মৃতিতে না রেখে?" অন্য কথায়, আমি একবারে এন টানার জন্য একটি ইন্টারফেস চাই, যেখানে এন 1 মিলিয়ন এর চেয়ে উল্লেখযোগ্য পরিমাণে ছোট। :-)
জর্জ আর্মহোল্ড

5

এটি করার কোনও "যথাযথ" নেই, এটি জেপিএ বা জেডিও বা অন্য কোনও ওআরএম করণীয় নয়, সোজা জেডিবিসি আপনার সেরা বিকল্প হবে, যেহেতু আপনি এটিকে অল্প সংখ্যক সারি ফিরিয়ে আনতে কনফিগার করতে পারেন at একটি সময় এবং সেগুলি যেমন ব্যবহৃত হয় তেমন ফ্লাশ করে, সেই কারণেই সার্ভার সাইড কার্সার বিদ্যমান।

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

উপযুক্ত সরঞ্জামটি ব্যবহার করুন। স্ট্রেট জেডিবিসি এবং সঞ্চিত প্রক্রিয়াগুলির স্পষ্টতই ২০১১ সালে একটি জায়গা রয়েছে, বিশেষত তারা এই ওআরএম ফ্রেমওয়ার্কগুলি বনাম কী করতে আরও ভাল।

কিছু মিলিয়নে টানতে, এমনকি কোনও সাধারণকে এমনকি List<Integer>আপনি এটি কীভাবেই করেন না কেন খুব কার্যকর হতে পারে না। আপনি যা জিজ্ঞাসা করছেন তা করার সঠিক উপায় হ'ল একটি সহজ SELECT id FROM table, সেট SERVER SIDE(ভেন্ডর নির্ভর) এবং এর উপর কার্সার FORWARD_ONLY READ-ONLYএবং পুনরাবৃত্তি।

আপনি যদি প্রত্যেকের সাথে কিছু ওয়েব সার্ভার কল করে প্রক্রিয়াজাত করতে লক্ষ লক্ষ আইডি টানছেন তবে কোনও যুক্তিসঙ্গত পরিমাণে চলতে আপনাকে কিছুটা সমবর্তী প্রক্রিয়াকরণও করতে হবে। একটি জেডিবিসি কার্সারের সাহায্যে টানুন এবং তাদের কয়েকটিকে একযোগে লিঙ্কযুক্ত কিউতে রেখে এবং থ্রেডের একটি ছোট পুল (# সিপিইউ / কোর +1) টানুন এবং তাদের প্রক্রিয়া করা কোনও মেশিনে আপনার কাজটি সম্পূর্ণ করার একমাত্র উপায় "" স্বাভাবিক "র‌্যামের পরিমাণ, প্রদত্ত আপনি ইতিমধ্যে স্মৃতিশক্তি শেষ।

এই উত্তরটিও দেখুন ।


1
সুতরাং আপনি বলছেন যে কোনও সংস্থাকে কখনই তাদের ব্যবহারকারীর টেবিলের প্রতিটি সারি দেখার প্রয়োজন নেই? তাদের প্রোগ্রামাররা যখন হাইবারনেটকে এই কাজ করার সময় আসে তখন কেবল উইন্ডোটি বাইরে ফেলে দেয়? " সেখানে সারি হাজার হাজার প্রক্রিয়া শত শত কোন উপায় নেই " - আমার প্রশ্ন আমি নির্দিষ্ট setFirstResult / setMaxResult, তাই পরিষ্কারভাবে সেখানে হয় একটি উপায়। আমি জিজ্ঞাসা করছি আরও ভাল আছে কিনা?
জর্জ আর্মহোল্ড

"কয়েক মিলিয়ন কিছুই টেনে আনতে, এমনকি একটি সাধারণ তালিকায় <ইন্টিজার> এমনকি আপনি কীভাবে এটিই করেন না কেন খুব কার্যকর হতে পারে না" " এটাই আমার বক্তব্য। আমি জিজ্ঞাসা করছি কীভাবে দৈত্য তালিকা তৈরি করবেন না , বরং ফলাফলের ফলাফলের মাধ্যমে পুনরাবৃত্তি করতে হবে।
জর্জ আর্মহোল্ড

আমার উত্তরে যেমন পরামর্শ দেওয়া হয়েছে তেমনি একটি সরল সরল জেডিবিসি নির্বাচনের বিবরণটি একটি ফরওয়ার্ডপোটিয়ালি রিডেটোপ্লাইয়ের সাথে একটি SERVER_SIDE কার্সার সহ ব্যবহার করুন। কীভাবে JDBC কে SERVER_SIDE কার্সার ব্যবহার করবেন তা হ'ল ডাটাবেস ড্রাইভার নির্ভর।

1
আমি সম্পূর্ণরূপে উত্তর সাথে একমত। সর্বোত্তম সমাধান সমস্যার উপর নির্ভরশীল। সমস্যাটি যদি কয়েকটি সত্তা সহজে লোড হয় তবে জেপিএ ভাল। যদি সমস্যাটি বিপুল পরিমাণে ডেটা ব্যবহার করে দক্ষতার সাথে সরাসরি জেডিবিসি করা ভাল।
এক্সেরেনন

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

4

আপনি অন্য "কৌশল" ব্যবহার করতে পারেন। আপনার আগ্রহী সত্তাগুলির সনাক্তকারীদের কেবল সংগ্রহ লোড করুন Say পরিচয়দাতা দীর্ঘ = 8 বাইটস টাইপ করুন, তারপরে 10 ^ 6 এর মতো সনাক্তকারীগুলির একটি তালিকা প্রায় 8Mb করে। যদি এটি একটি ব্যাচ প্রক্রিয়া (একবারে এক উদাহরণ) হয় তবে তা সহনীয়। তারপরে কেবল পুনরাবৃত্তি করুন এবং কাজটি করুন।

আরেকটি মন্তব্য - আপনার যাইহোক খণ্ডগুলিতে এটি করা উচিত - বিশেষত যদি আপনি রেকর্ডগুলি সংশোধন করেন, অন্যথায় ডাটাবেসে রোলব্যাক অংশটি বৃদ্ধি পাবে।

যখন প্রথম রেজাল্ট / ম্যাক্সরউস কৌশল সেট করার কথা আসে - উপরে থেকে ফলাফলের জন্য এটি খুব ধীরে ধীরে হবে ।

এটিও বিবেচনায় রাখুন যে সম্ভবত ডাটাবেসগুলি পঠিত বিচ্ছিন্ন বিচ্ছিন্নতায় কাজ করছে , তাই ভুতটি পড়তে লোড শনাক্তকারীদের এড়াতে এবং তারপরে একের পর এক (বা 10 দ্বারা 10 বা যা কিছু) লোড সত্তা লোড করে।


হাই @ মার্সিন, আপনি বা অন্য কেউ উদাহরণস্বরূপ জাভা 8 টি স্ট্রিম ব্যবহার করে এই চন্ডযুক্ত এবং আইডি-প্রথম ধাপের দিকের পদ্ধতির প্রয়োগ কোডের একটি লিঙ্ক সরবরাহ করতে পারেন?
krevelen

2

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

এখানে পারফরম্যান্স সঞ্চয়গুলি তাৎপর্যপূর্ণ, সম্ভবত আপনি জেপিএ / হাইবারনেট / অ্যাপসার্ভার জমিতে যা কিছু করতে পারেন তার চেয়ে দ্রুতগতির অর্ডার এবং আপনার ডাটাবেস সার্ভারে দক্ষতার সাথে বড় ফলাফলের সেটগুলি কার্যকরভাবে প্রক্রিয়াকরণের জন্য নিজস্ব সার্ভার সাইড কার্সার ধরণের প্রক্রিয়া থাকবে। কর্মক্ষমতা সঞ্চয়গুলি ডাটাবেস সার্ভার থেকে অ্যাপ্লিকেশন সার্ভারে ডেটা না পাঠানো থেকে আসে, যেখানে আপনি ডেটা প্রক্রিয়া করে এবং তারপরে এটি আবার শিপ করে।

সঞ্চিত প্রক্রিয়াগুলি ব্যবহার করার জন্য কিছু উল্লেখযোগ্য ডাউনসাইড রয়েছে যা এটি আপনার জন্য সম্পূর্ণভাবে বিস্মৃত হতে পারে তবে আপনি যদি নিজের ব্যক্তিগত সরঞ্জাম বাক্সে দক্ষতা পেয়ে থাকেন এবং এই জাতীয় পরিস্থিতিতে এটি ব্যবহার করতে পারেন তবে আপনি এই ধরণের জিনিসগুলি মোটামুটি দ্রুত নক করতে পারেন ।


1
-2 ডাউনভোটস - পরের ডাউনভোটার দয়া করে আপনার ডাউনটোটকে ডিফেন্ড করবেন?
বিপদ

1
এগুলি পড়ার সময় আমিও একই জিনিস ভেবেছিলাম। প্রশ্নটি কোনও UI ছাড়াই একটি উচ্চ ভলিউম ব্যাচের কাজের সূচিত করে। ধরে নিচ্ছি যে আপনার অ্যাপ্লিকেশন সার্ভারের নির্দিষ্ট সংস্থান দরকার নেই, কেন কোনও অ্যাপ সার্ভার ব্যবহার করবেন না? সঞ্চিত পদ্ধতিটি আরও কার্যকর হবে।
jdessey

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

1

@ টমাসজ নুরকিউইকের উত্তরটি প্রসারিত করতে। DataSourceঘুরেফিরে আপনাকে একটি সংযোগ সরবরাহ করতে পারে এমন আপনার অ্যাক্সেস রয়েছে

@Resource(name = "myDataSource",
    lookup = "java:comp/DefaultDataSource")
private DataSource myDataSource;

আপনার কোডে

try (Connection connection = myDataSource.getConnection()) {
    // raw jdbc operations
}

এটি আপনাকে আমদানি / রফতানির মতো কিছু নির্দিষ্ট বৃহত ব্যাচের ক্রিয়াকলাপের জন্য জেপিএকে বাইপাস করার অনুমতি দেবে, তবে আপনার যদি প্রয়োজন হয় তবে অন্যান্য জেপিএ ক্রিয়াকলাপগুলির সত্তা ব্যবস্থাপকের কাছে অ্যাক্সেস রয়েছে।


0

Paginationফলাফল পুনরুদ্ধারের জন্য ধারণাটি ব্যবহার করুন


4
পৃষ্ঠাগুলি জিইউআই এর জন্য খুব ভাল। তবে বিপুল পরিমাণে ডেটা প্রক্রিয়াকরণের জন্য স্ক্রোলবেলসাল্টসেট আবিষ্কার হয়েছিল অনেক আগে time এটা ঠিক জেপিএ তে নয়।
এক্সেরেনন

0

আমি নিজেই এই বিষয়টি অবাক করেছি। এটি মনে হচ্ছে:

  • আপনার ডেটাসেটটি কত বড় (সারি)
  • আপনি কী ব্যবহার করছেন JPA বাস্তবায়ন
  • আপনি প্রতিটি সারিতে কী ধরনের প্রক্রিয়াজাতকরণ করছেন।

উভয় পন্থা (ফাইন্ডএল বনাম ফাইন্ড এন্ট্রিগুলি) সহজেই সরিয়ে আনা সহজ করার জন্য আমি একটি আইট্রেটর লিখেছি।

আমি আপনাকে উভয় চেষ্টা করার পরামর্শ দিচ্ছি।

Long count = entityManager().createQuery("select count(o) from Model o", Long.class).getSingleResult();
ChunkIterator<Model> it1 = new ChunkIterator<Model>(count, 2) {

    @Override
    public Iterator<Model> getChunk(long index, long chunkSize) {
        //Do your setFirst and setMax here and return an iterator.
    }

};

Iterator<Model> it2 = List<Model> models = entityManager().createQuery("from Model m", Model.class).getResultList().iterator();


public static abstract class ChunkIterator<T> 
    extends AbstractIterator<T> implements Iterable<T>{
    private Iterator<T> chunk;
    private Long count;
    private long index = 0;
    private long chunkSize = 100;

    public ChunkIterator(Long count, long chunkSize) {
        super();
        this.count = count;
        this.chunkSize = chunkSize;
    }

    public abstract Iterator<T> getChunk(long index, long chunkSize);

    @Override
    public Iterator<T> iterator() {
        return this;
    }

    @Override
    protected T computeNext() {
        if (count == 0) return endOfData();
        if (chunk != null && chunk.hasNext() == false && index >= count) 
            return endOfData();
        if (chunk == null || chunk.hasNext() == false) {
            chunk = getChunk(index, chunkSize);
            index += chunkSize;
        }
        if (chunk == null || chunk.hasNext() == false) 
            return endOfData();
        return chunk.next();
    }

}

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


"আপনি প্রতিটি সারির জন্য কী ধরণের প্রক্রিয়াকরণ করছেন" - যদি সারিগুলির সংখ্যা কয়েক মিলিয়ন হয় তবে আমি সন্দেহ করি যে কেবল একটি আইডি কলাম সহ একটি সাধারণ বস্তুও সমস্যা সৃষ্টি করতে পারে। আমি নিজেই নিজের আইট্রেটার লিখার কথা ভেবেছিলাম যা সেটফার্সআরসাল্ট / সেটম্যাক্সরেসাল্টকে জড়িয়ে রেখেছে, তবে আমি বুঝতে পেরেছি এটি অবশ্যই একটি সাধারণ (এবং আশাকরি সমাধান করা) সমস্যা হতে পারে।
জর্জ আর্মহোল্ড

@ ক্যাফিন কোমা আমি আমার ইটারেটর পোস্ট করেছি আপনি সম্ভবত এটির সাথে আরও কিছু জেপিএ মানিয়ে নিতে পারেন। যদি এটি সাহায্য করে তবে আমাকে বলুন। আমি ব্যবহার না করে শেষ করেছি (সমস্ত অনুসন্ধান করলাম)।
অ্যাডাম জেন্ট

0

হাইবারনেট সহ আপনি যা চান তা অর্জনের জন্য 4 টি বিভিন্ন উপায় রয়েছে। প্রত্যেকের ডিজাইন ট্রেড অফস, সীমাবদ্ধতা এবং ফলাফল রয়েছে। আমি প্রত্যেককে অন্বেষণ করার এবং আপনার অবস্থার জন্য কোনটি ঠিক করার সিদ্ধান্ত নেওয়ার পরামর্শ দিচ্ছি।

  1. স্ক্রোল সহ স্টেটলেস সেশন ব্যবহার করুন ()
  2. প্রতিটি পুনরাবৃত্তির পরে সেশন.ক্রিয়ার () ব্যবহার করুন। যখন অন্যান্য সত্তাগুলি সংযুক্ত করা দরকার, তখন সেগুলি একটি পৃথক সেশনে লোড করুন। কার্যকরভাবে প্রথম অধিবেশনটি রাষ্ট্রবিহীন অধিবেশনকে অনুকরণ করে তবে অবজেক্টগুলি বিচ্ছিন্ন না করা পর্যন্ত রাষ্ট্রীয় অধিবেশনটির সমস্ত বৈশিষ্ট্য ধরে রাখে।
  3. পুনরাবৃত্তি () বা তালিকা () ব্যবহার করুন তবে প্রথম ক্যোয়ারীতে কেবল আইডিগুলি পান, তারপরে প্রতিটি পুনরাবৃত্তির পৃথক সেশনে সেশন করুন session লোড করুন এবং পুনরাবৃত্তির শেষে সেশনটি বন্ধ করুন।
  4. এন্টি ম্যানেজ.ডেটাচ () ওরফে সেশন.এভিক্ট () সহ কোয়েরি.আইরেট () ব্যবহার করুন;

0

এখানে একটি সরল, সোজা জেপিএ উদাহরণ (কোটলিনে) আপনি কীভাবে একটি কার্সার ব্যবহার না করে একসাথে 100 টি আইটেমের অংশগুলি পড়তে চান তা নির্ধারণ করতে পারেন তা দেখায় (প্রতিটি কার্সার ডাটাবেসে সংস্থান ব্যবহার করে)। এটিতে কীসেট প্যাগিনেশন ব্যবহার করা হয়েছে।

কীসেট পৃষ্ঠাগুলির ধারণার জন্য https://use-the-index-luke.com/no-offset দেখুন এবং https://www.citusdata.com/blog/2016/03/30/five-ways-to- পৃষ্ঠাগুলি / তাদের ত্রুটিগুলি সহ প্যাগিনেট করার বিভিন্ন উপায়ের সাথে তুলনা করার জন্য।

/*
create table my_table(
  id int primary key, -- index will be created
  my_column varchar
)
*/

fun keysetPaginationExample() {
    var lastId = Integer.MIN_VALUE
    do {

        val someItems =
        myRepository.findTop100ByMyTableIdAfterOrderByMyTableId(lastId)

        if (someItems.isEmpty()) break

        lastId = someItems.last().myTableId

        for (item in someItems) {
          process(item)
        }

    } while (true)
}

0

জেপিএ এবং নেটিভিক্যু কিউরির সাথে অফসেটগুলি ব্যবহার করে প্রতিটি সময় আকারের উপাদানগুলি আনার একটি উদাহরণ

public List<X> getXByFetching(int fetchSize) {
        int totalX = getTotalRows(Entity);
        List<X> result = new ArrayList<>();
        for (int offset = 0; offset < totalX; offset = offset + fetchSize) {
            EntityManager entityManager = getEntityManager();
            String sql = getSqlSelect(Entity) + " OFFSET " + offset + " ROWS";
            Query query = entityManager.createNativeQuery(sql, X.class);
            query.setMaxResults(fetchSize);
            result.addAll(query.getResultList());
            entityManager.flush();
            entityManager.clear();
        return result;
    }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.