রিলেশনাল ডেটাবেসে অর্ডার করা তথ্য কীভাবে সংরক্ষণ করবেন


20

আমি কীভাবে কোনও সম্পর্কিত ডেটাবেসে অর্ডার করা তথ্য সঠিকভাবে সঞ্চয় করতে হয় তা বোঝার চেষ্টা করছি।

একটি উদাহরণ:

বলুন আমার কাছে একটি প্লেলিস্ট আছে, এতে গান রয়েছে। আমার রিলেশনাল ডেটাবেস এর ভিতরে আমার একটি টেবিল রয়েছে Playlists, এতে কিছু মেটাডেটা (নাম, স্রষ্টা, ইত্যাদি) রয়েছে। আমার কাছে একটি টেবিলও রয়েছে Songs, এতে একটি রয়েছে playlist_id, সেইসাথে গান-নির্দিষ্ট তথ্য (নাম, শিল্পী, সময়কাল ইত্যাদি)।

ডিফল্টরূপে, যখন কোনও প্লেলিস্টে একটি নতুন গান যুক্ত হয়, এটি শেষের সাথে যুক্ত হয়। গান-আইডি (আরোহণ) এ অর্ডার দেওয়ার সময়, আদেশটি যোগ করার ক্রম হবে। তবে যদি কোনও ব্যবহারকারীর প্লেলিস্টে গানগুলি পুনরায় অর্ডার করতে সক্ষম হয় তবে কী হবে?

আমি কয়েকটি সুবিধা এবং অসুবিধাগুলি নিয়ে কয়েকটি ধারণা নিয়ে এসেছি:

  1. একটি কলাম বলা হয় order, যা একটি পূর্ণসংখ্যা । যখন কোনও গান সরানো হয়, তার পুরানো এবং নতুন অবস্থানের মধ্যে সমস্ত গানের ক্রম পরিবর্তন করা হয়, পরিবর্তনের প্রতিফলন করতে। এর অপূর্ণতা হ'ল প্রতিবার একটি গান সরানোর সময় প্রচুর প্রশ্ন করা দরকার, এবং চলমান অ্যালগরিদম অন্যান্য বিকল্পগুলির মতো তুচ্ছ নয়।
  2. একটি কলাম বলা হয় order, যা দশমিক ( NUMERIC)। যখন একটি গান সরানো হয়, তখন এটি দুটি সংলগ্ন সংখ্যার মধ্যে ভাসমান পয়েন্ট মান নির্ধারিত হয়। খসড়া: দশমিক ক্ষেত্রগুলি আরও স্থান নেয় এবং যথাযথতার বাইরে চলে যাওয়া সম্ভব হতে পারে, যদি না প্রতি কয়েকটি পরিবর্তনের পরে পরিসীমাটিকে পুনরায় বিতরণের যত্ন নেওয়া হয়।
  3. আর একটি উপায় হ'ল এমন previousএকটি nextক্ষেত্র যা অন্যান্য গানের রেফারেন্স দেয়। (বা এখনই প্লেলিস্টে প্রথম, শ্রদ্ধার সাথে সর্বশেষ গানটির ক্ষেত্রে ন্যূনুয়াল; মুলত আপনি একটি লিঙ্ক-তালিকা তৈরি করেন )। খসড়া: 'তালিকায় Xth সং সন্ধান করুন' এর মতো অনুসন্ধানগুলি আর ধ্রুবক-সময় নয়, পরিবর্তে লিনিয়ার-সময়।

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

সম্পাদনা: সরলতার জন্য, উদাহরণে একটি গান কেবল একটি প্লেলিস্টের (একাধিক টু ওয়ান সম্পর্ক) এর অন্তর্ভুক্ত। অবশ্যই, কেউ জংশন সারণীটিও ব্যবহার করতে পারে তাই গানের প্লেলিস্ট হ'ল একাধিক থেকে অনেকের সম্পর্ক (এবং উপরের কৌশলগুলির মধ্যে একটিটি সেই টেবিলটিতে প্রয়োগ করুন)।


1
আপনি 100-পদক্ষেপের সাহায্যে বিকল্প এক (পূর্ণসংখ্যা হিসাবে অর্ডার) ব্যবহার করতে পারেন। তারপরে আপনার যদি কোনও গান সরানো থাকে তবে আপনার কোনও পুনঃ-অর্ডার দরকার নেই, কেবল 100 এর মধ্যে একটি মান নিন time গানের মাঝে আবার ফাঁক পেতে আপনার প্রয়োজন হতে পারে নতুন পুনর্বাসনের প্রয়োজন।
knut

4
"এর অপূর্ণতা হ'ল প্রতিবার একটি গান সরানোর সময় অনেক প্রশ্ন করা দরকার" ?! - update songorder set order = order - 1 where order >= 12 & order <= 42; update songorder set order = 42 where id = 123;- এটি দুটি আপডেট - ত্রিশ নয়। তিনটি যদি আপনি আদেশে একটি অনন্য বাধা রাখতে চান।

2
আপনার যদি অন্য কোনও প্রয়োজনের সত্যতা না জেনে থাকে তবে বিকল্প বিকল্পটি ব্যবহার করুন। ডাটাবেসগুলির মুখোমুখি হওয়া নতুন একটি সমস্যা প্রোগ্রামাররা বুঝতে পারে না যে এই ধরণের ক্ষেত্রে ডাটাবেসগুলি খুব খুব ভাল। আপনার ডিবি কাজে লাগাতে ভয় পাবেন না।
গ্র্যান্ডমাস্টারবি

1
Queries like 'find the Xth Song in the list' are no longer constant-timeএছাড়াও বিকল্পের জন্য 2. সত্য
ডক ব্রাউন

2
@ মাইকনাকিস: এটি ব্যয়বহুল বলে মনে হচ্ছে, তবে সার্ভারে সমস্ত কাজ করা হচ্ছে, যা (সাধারণত) এই ধরণের কাজের জন্য অনুকূলিত হয়। আমি কয়েক মিলিয়ন সারি সহ একটি টেবিলটিতে এই কৌশলটি ব্যবহার করব না, তবে আমি কেবল কয়েক হাজার সহ একটি টেবিলের জন্য ছাড় দেব না।
টিএমএন

উত্তর:


29

ডাটাবেসগুলি নির্দিষ্ট জিনিসের জন্য অনুকূলিত হয়। প্রচুর সারি দ্রুত আপডেট করা তার মধ্যে একটি। এটি বিশেষভাবে সত্য হয়ে যায় যখন আপনি ডাটাবেসটির কাজটি করতে দেন।

বিবেচনা:

order song
1     Happy Birthday
2     Beat It
3     Never Gonna Give You Up
4     Safety Dance
5     Imperial March

এবং আপনি Beat Itশেষের দিকে যেতে চান , আপনার দুটি প্রশ্ন থাকবে:

update table 
  set order = order - 1
  where order >= 2 and order <= 5;

update table
  set order = 5
  where song = 'Beat It'

এবং এটাই. এটি খুব বড় সংখ্যক দিয়ে খুব ভালভাবে স্কেল করে। আপনার ডেটাবেজে অনুমানমূলক প্লেলিস্টে কয়েক হাজার গান রাখার চেষ্টা করুন এবং দেখুন যে গানটি এক অবস্থান থেকে অন্য স্থানে নিয়ে যেতে কত সময় নেয়। এগুলির খুব মানক রূপ রয়েছে:

update table 
  set order = order - 1
  where order >= ? and order <= ?;

update table
  set order = ?
  where song = ?

আপনার দুটি প্রস্তুত বিবৃতি রয়েছে যা আপনি খুব দক্ষতার সাথে পুনরায় ব্যবহার করতে পারেন।

এটি কিছু উল্লেখযোগ্য সুবিধা সরবরাহ করে - টেবিলের ক্রম এমন একটি বিষয় যা সম্পর্কে আপনি যুক্তিযুক্ত হতে পারেন। তৃতীয় গানে orderসর্বদা 3 এর 3 টি রয়েছে। এটির গ্যারান্টি দেওয়ার একমাত্র উপায় হ'ল আদেশ হিসাবে একটানা পূর্ণসংখ্যা ব্যবহার করা। সিউডো-লিঙ্কযুক্ত তালিকাগুলি বা দশমিক সংখ্যা বা শূন্যস্থান সহ পূর্ণসংখ্যার ব্যবহার আপনাকে এই সম্পত্তি গ্যারান্টি দেয় না; এই ক্ষেত্রে নবম সংগীত পাওয়ার একমাত্র উপায় হ'ল পুরো টেবিলটি বাছাই করা এবং নবম রেকর্ডটি পাওয়া।

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


2
আমি এই পদ্ধতির পছন্দ করতে শুরু করছি।
মাইক নকিস

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

orderযেহেতু order byমূল শব্দটি ব্যবহার করে কোনও সমস্যা হবে ?
kojow7

@ কোজো,, যদি আপনার ক্ষেত্রগুলির কীওয়ার্ডগুলির সাথে বিরোধের নাম রয়েছে তবে আপনার সেগুলি টিকমার্কগুলিতে "` "মোড়ানো উচিত।
Andri

এই পদ্ধতির অর্থ উপলব্ধি করে তবে orderপ্লেলিস্টে কোনও নতুন গান যুক্ত করার সময় মানটি পাওয়ার সর্বোত্তম উপায় কী । , এটা 9 ম গান ধরুন সেখানে প্রবেশ 9 সন্নিবেশ করতে কোন ভাল উপায় নেই orderএকটি করছেন চেয়ে COUNTরেকর্ড যোগ করার পূর্বে?
delashum

3

প্রথমত, আপনি কী করেছেন তার বিবরণ থেকে এটি স্পষ্ট নয়, তবে আপনার একটি PlaylistSongsটেবিলের প্রয়োজন যা একটি PlaylistIdএবং একটি ধারণ করে SongId, কোন গানটি কোন প্লেলিস্টের অন্তর্ভুক্ত তা বর্ণনা করে।

এই টেবিলের মধ্যেই আপনাকে ক্রম সম্পর্কিত তথ্য যোগ করতে হবে।

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

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

শ্রেণিটি ParameterTemplate(যাই হোক না কেন, জিজ্ঞাসা করবেন না!) পদ্ধতিটি প্যারামিটার টেম্পলেটগুলির তালিকা পায় যা এই টেম্পলেটটি তার পিতামাতার অন্তর্ভুক্ত ActivityTemplate। (যাই হোক না কেন, জিজ্ঞাসা করবেন না!) কোডটিতে নির্ভুলতার বাইরে চলে যাওয়ার বিরুদ্ধে কিছু রক্ষী রয়েছে। বিভাজকটি পরীক্ষার জন্য ব্যবহৃত হয়: ইউনিট পরীক্ষায় একটি বৃহৎ বিভাজক ব্যবহার করা হয় যাতে দ্রুত নির্ভুলতার বাইরে চলে যায় এবং এইভাবে নির্ভুলতা রক্ষণাবেক্ষণের কোডটি ট্রিগার করে। দ্বিতীয় পদ্ধতিটি সর্বজনীন এবং "কেবল অভ্যন্তরীণ ব্যবহারের জন্য; অনুরোধ করবেন না" যাতে পরীক্ষার কোডটি এটি করতে পারে। (এটা প্যাকেজ-ব্যক্তিগত হতে পারে না কারণ আমার পরীক্ষামূলক কোড কোড এটা পরীক্ষাগুলির মত একই প্যাকেজের মধ্যে নয়।) ক্ষেত্র যা ক্রম নিয়ন্ত্রণ বলা হয় Ordering, মাধ্যমে অ্যাক্সেস getOrdering()এবং setOrdering()। আপনি কোনও এসকিউএল দেখতে পাবেন না কারণ আমি হাইবারনেটের মাধ্যমে অবজেক্ট-রিলেশনাল ম্যাপিং ব্যবহার করছি।

/**
 * Moves this {@link ParameterTemplate} to the given index in the list of {@link ParameterTemplate}s of the parent {@link ActivityTemplate}.
 *
 * The index must be greater than or equal to zero, and less than or equal to the number of entries in the list.  Specifying an index of zero will move this item to the top of
 * the list. Specifying an index which is equal to the number of entries will move this item to the end of the list.  Any other index will move this item to the position
 * specified, also moving other items in the list as necessary. The given index cannot be equal to the current index of the item, nor can it be equal to the current index plus
 * one.  If the given index is below the current index of the item, then the item will be moved so that its new index will be equal to the given index.  If the given index is
 * above the current index, then the new index of the item will be the given index minus one.
 *
 * NOTE: this method flushes the persistor and refreshes the parent node so as to guarantee that the changes will be immediately visible in the list of {@link
 * ParameterTemplate}s of the parent {@link ActivityTemplate}.
 *
 * @param toIndex the desired new index of this {@link ParameterTemplate} in the list of {@link ParameterTemplate}s of the parent {@link ActivityTemplate}.
 */
public void moveAt( int toIndex )
{
    moveAt( toIndex, 2.0 );
}

/**
 * For internal use only; do not invoke.
 */
public boolean moveAt( int toIndex, double divisor )
{
    MutableList<ParameterTemplate<?>> parameterTemplates = getLogicDomain().getMutableCollections().newArrayList();
    parameterTemplates.addAll( getParentActivityTemplate().getParameterTemplates() );
    assert parameterTemplates.getLength() >= 1; //guaranteed since at the very least, this parameter template must be in the list.
    int fromIndex = parameterTemplates.indexOf( this );
    assert 0 <= toIndex;
    assert toIndex <= parameterTemplates.getLength();
    assert 0 <= fromIndex;
    assert fromIndex < parameterTemplates.getLength();
    assert fromIndex != toIndex;
    assert fromIndex != toIndex - 1;

    double order;
    if( toIndex == 0 )
    {
        order = parameterTemplates.fetchFirstElement().getOrdering() - 1.0;
    }
    else if( toIndex == parameterTemplates.getLength() )
    {
        order = parameterTemplates.fetchLastElement().getOrdering() + 1.0;
    }
    else
    {
        double prevOrder = parameterTemplates.get( toIndex - 1 ).getOrdering();
        parameterTemplates.moveAt( fromIndex, toIndex );
        double nextOrder = parameterTemplates.get( toIndex + (toIndex > fromIndex ? 0 : 1) ).getOrdering();
        assert prevOrder <= nextOrder;
        order = (prevOrder + nextOrder) / divisor;
        if( order <= prevOrder || order >= nextOrder ) //if the accuracy of the double has been exceeded
        {
            parameterTemplates.clear();
            parameterTemplates.addAll( getParentActivityTemplate().getParameterTemplates() );
            for( int i = 0; i < parameterTemplates.getLength(); i++ )
                parameterTemplates.get( i ).setOrdering( i * 1.0 );
            rocs3dDomain.getPersistor().flush();
            rocs3dDomain.getPersistor().refresh( getParentActivityTemplate() );
            moveAt( toIndex );
            return true;
        }
    }
    setOrdering( order );
    rocs3dDomain.getPersistor().flush();
    rocs3dDomain.getPersistor().refresh( getParentActivityTemplate() );
    assert getParentActivityTemplate().getParameterTemplates().indexOf( this ) == (toIndex > fromIndex ? toIndex - 1 : toIndex);
    return false;
}

আমি একটি পূর্ণসংখ্যার ক্রম ব্যবহার করব এবং যদি আমার মনে হয় যে পুনঃক্রমটি খুব ব্যয়বহুল ছিল, আমি কেবল এক্স দ্বারা প্রতিটি লাফ দিয়ে, পুনরায় ক্রমের সংখ্যা হ্রাস করব, যেখানে এক্সটি এমন পরিমাণ যা আমার দ্বারা পুনরায় ক্রম হ্রাস করতে হবে, 20 বলুন, যা স্টার্টার হিসাবে ভাল হতে হবে।
ওয়ারেন পি

1
@ ওয়ারেনপ হ্যাঁ, আমি জানি, এটিও এইভাবে করা যেতে পারে, এজন্য আমি কেবল "সেরা" বা "এক" পদ্ধতির পরিবর্তে এই "আমার প্রিয়" পদ্ধতির কথা বলেছি।
মাইক নকিস

0

আমার জন্য কী কাজ করেছে, 100 আইটেমের ক্রমের একটি ছোট তালিকার জন্য একটি হাইব্রিড পদ্ধতি গ্রহণ করা হয়েছিল:

  1. দশমিক সাজানোর অর্ডার কলাম, তবে 0.5 পার্থক্য (যেমন দশমিক (8,2) বা কিছু) সঞ্চয় করার জন্য যথেষ্ট যথার্থতার সাথে।
  2. বাছাই করার সময়, সারিটির পিকেগুলি উপরে এবং নীচে ধরুন যেখানে বর্তমান সারি সবেমাত্র সরিয়ে নেওয়া হয়েছিল, যদি সেগুলির উপস্থিত থাকে। (উদাহরণস্বরূপ, আপনি যদি আইটেমটিকে প্রথম অবস্থানে নিয়ে যান তবে আপনার উপরে একটি সারি থাকবে না)
  3. বাছাই করার জন্য সার্ভারে বর্তমান, পূর্ব এবং পরবর্তী সারির পিকেগুলি পোস্ট করুন।
  4. আপনার যদি পূর্ববর্তী সারি থাকে তবে বর্তমান সারির অবস্থানটি পূর্বের + 0.5 তে সেট করুন। আপনার যদি কেবল পরবর্তী থাকে তবে বর্তমান সারির অবস্থানটি পরবর্তী - 0.5 তে সেট করুন।
  5. এর পরে আমার একটি স্টোরড প্রো আছে যা এসকিউএল সার্ভার Row_Number ফাংশনটি ব্যবহার করে সমস্ত অবস্থান আপডেট করে, নতুন সাজানোর ক্রম অনুসারে ক্রম করে। এটি অর্ডারটিকে 1,1.5,2,3,4,6 থেকে 1,2,3,4,5,6 এ রূপান্তর করবে, যেহেতু সারি_সংখ্যার ফাংশন আপনাকে পূর্ণসংখ্যার অর্ডিনাল দেয়।

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

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