এলোমেলো অর্ডার পাওয়ার সেরা উপায় কী?


27

আমার একটি ক্যোয়ারী রয়েছে যেখানে আমি ফলশ্রুতি রেকর্ডগুলি এলোমেলোভাবে অর্ডার করতে চাই। এটি একটি ক্লাস্টার্ড সূচক ব্যবহার করে, সুতরাং আমি যদি order byএটি অন্তর্ভুক্ত না করি তবে এটি সম্ভবত সেই সূচির ক্রমে রেকর্ডগুলি ফিরিয়ে আনবে। আমি কীভাবে একটি এলোমেলো সারি অর্ডার নিশ্চিত করতে পারি?

আমি বুঝতে পারি যে এটি সম্ভবত "সত্যিকারের" এলোমেলো হবে না, সিউডো-এলোমেলো আমার প্রয়োজনের জন্য যথেষ্ট ভাল।

উত্তর:


19

অর্ডার বাই নিউড () রেকর্ডগুলি এলোমেলোভাবে সাজবে। এখানে একটি উদাহরণ

SELECT *
FROM Northwind..Orders 
ORDER BY NEWID()

7
অর্ডার বাই নিউড () কার্যকরভাবে এলোমেলো, তবে পরিসংখ্যানগতভাবে এলোমেলো নয়। একটি সামান্য পার্থক্য আছে, এবং বেশিরভাগ সময় পার্থক্য কোন ব্যাপার না।
mrdenny

4
পারফরম্যান্সের দৃষ্টিকোণ থেকে, এটি বেশ ধীর - আপনি অর্ডার বাই চেকসাম (নিউড ())
মাইলস ডি

1
@ এমআরডেনি - আপনি "পরিসংখ্যানগতভাবে এলোমেলো নয়" কে ভিত্তি করছেন? উত্তর এখানে বলে যে এটি শেষ পর্যন্ত ব্যবহার CryptGenRandomকরে শেষ হয়। dba.stackexchange.com/a/208069/3690
মার্টিন স্মিথ

15

প্রদীপ আদিগার প্রথম পরামর্শ, ORDER BY NEWID()ঠিক আছে এবং আমি অতীতে এই কারণে ব্যবহার করেছি।

ব্যবহারের সাথে সতর্কতা অবলম্বন করুন RAND()- অনেকগুলি প্রসঙ্গে এটি প্রতি বিবৃতিতে একবার কার্যকর ORDER BY RAND()করা হয় যার ফলে কোনও প্রভাব পড়বে না (যেমন আপনি প্রতিটি সারির জন্য RAND () এর বাইরে একই ফলাফল পাচ্ছেন)।

এই ক্ষেত্রে:

SELECT display_name, RAND() FROM tr_person

আমাদের ব্যক্তির টেবিল থেকে প্রতিটি নাম এবং একটি "এলোমেলো" নম্বর দেয়, যা প্রতিটি সারির জন্য একই। প্রতিবার আপনি ক্যোয়ারি চালানোর সময় সংখ্যাটি পৃথক হয়, তবে প্রতিবারের জন্য প্রতিটি সারির জন্য একই is

RAND()একটি ORDER BYধারাতে ব্যবহৃত একই ক্ষেত্রে এটি দেখাতে , আমি চেষ্টা করি:

SELECT display_name FROM tr_person ORDER BY RAND(), display_name

ফলাফলগুলি এখনও নামের সাথে অর্ডার করা হয় যে ইঙ্গিত করে যে পূর্ববর্তী সাজানো ক্ষেত্রটি (যেটি এলোমেলোভাবে প্রত্যাশিত ছিল) এর কোনও প্রভাব নেই সম্ভবত সম্ভবত সর্বদা একই মান থাকে has

দ্বারা ক্রমানুসার NEWID()কারন যদি NEWID () করা হয় নি, যদিও কাজ করে সবসময় যখন অনন্য শনাক্তকারী সঙ্গে এক statemnt অনেক নতুন সারি ঢোকাতে reassessed UUID জানা উদ্দেশ্য ভেঙে ফেলা হবে তারা কী, তাই:

SELECT display_name FROM tr_person ORDER BY NEWID()

নেই নাম "এলোমেলোভাবে" অর্ডার।

অন্যান্য ডিবিএমএস

উপরেরটি এমএসএসকিউএল এর জন্য সত্য (কমপক্ষে ২০০ and এবং ২০০৮, এবং আমি যদি সঠিকভাবে 2000 মনে করি তবে)। একটি নতুন UUID উপস্থাপন করা ফাংশন উচিত সব DBMSs NEWID (ইন প্রত্যেক সময় মূল্যায়ন করা) এমএস স্কুয়েল বয়সী কিন্তু এটি ডকুমেন্টেশন এই যাচাই এবং / অথবা আপনার নিজের পরীক্ষার দ্বারা মূল্য। অন্যান্য স্বেচ্ছাসেবী-ফলাফল ফাংশনগুলির মতো, যেমন RAND () এর ব্যবহার DBMS- এর মধ্যে পরিবর্তিত হওয়ার সম্ভাবনা বেশি থাকে, তাই আবার ডকুমেন্টেশন পরীক্ষা করে দেখুন।

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

সাইড নোট

আপনি যদি একটি স্বেচ্ছাসেবী কিন্তু কিছুটা পুনরাবৃত্তিযোগ্য অর্ডারিং চান তবে সারিগুলিতে থাকা কিছু অপেক্ষাকৃত অনিয়ন্ত্রিত উপসেটটি অর্ডার করুন। উদাহরণস্বরূপ হয় বা এগুলি একটি স্বেচ্ছাচারিত তবে পুনরাবৃত্তিযোগ্য ক্রমে নামগুলি ফিরিয়ে দেবে:

SELECT display_name FROM tr_person ORDER BY CHECKSUM(display_name), display_name -- order by the checksum of some of the row's data
SELECT display_name FROM tr_person ORDER BY SUBSTRING(display_name, LEN(display_name)/2, 128) -- order by part of the name field, but not in any an obviously recognisable order)

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

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

কর্মক্ষমতা

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


14

এটি একটি পুরানো প্রশ্ন, তবে আলোচনার একটি দিক অনুপস্থিত, আমার মতে - পারফর্মেন্স। ORDER BY NewId()সাধারণ উত্তর। তারা যোগ করেন, তখন কেউ পেতে এর অভিনব যে আপনি কি সত্যিই মোড়ানো উচিত NewID()মধ্যে CheckSum(), আপনি পারফরম্যান্সের জন্য জানি!

এই পদ্ধতির সমস্যাটি হ'ল আপনি এখনও একটি পূর্ণ সূচী স্ক্যান এবং তারপরে একটি সম্পূর্ণ ধরণের ডেটা গ্যারান্টিযুক্ত। আপনি যদি কোনও গুরুতর ডেটা ভলিউম নিয়ে কাজ করেন তবে এটি দ্রুত ব্যয়বহুল হতে পারে। এই সাধারণ সম্পাদন পরিকল্পনাটি দেখুন এবং নোট করুন যে কীভাবে আপনার সময়ের 96% সময় নেয় ...

এখানে চিত্র বর্ণনা লিখুন

এই স্কেলগুলি কীভাবে আপনাকে বোঝানোর জন্য, আমি আপনার সাথে কাজ করি এমন একটি ডাটাবেস থেকে দুটি উদাহরণ দেব।

  • টেবিলএ - 2500 ডেটা পৃষ্ঠাগুলি জুড়ে 50,000 সারি রয়েছে। এলোমেলো ক্যোয়ারী 145 টি পাঠায় 42 মিমি উত্পন্ন করে।
  • সারণি বি - এর 114,000 ডেটা পৃষ্ঠাগুলিতে 1.2 মিলিয়ন সারি রয়েছে। Order By newid()এই টেবিলটিতে চালানো 53,700 টি পঠন করে এবং 16 সেকেন্ড সময় নেয়।

গল্পটির নৈতিকতাটি হ'ল যদি আপনার কাছে বড় টেবিল থাকে (বিলিয়ন সারি ভাবেন) বা প্রায়শই এই কোয়েরিটি চালানোর প্রয়োজন হয় তবে newid()পদ্ধতিটি ভেঙে যায়। তাহলে একটা ছেলে কী করবে?

সারণীর নমুনা দেখা ()

এসকিউএল 2005-তে একটি নতুন দক্ষতা তৈরি TABLESAMPLEহয়েছিল। আমি কেবল একটি নিবন্ধ দেখেছি এটির ব্যবহার নিয়ে আলোচনা করছে ... আরও কিছু হওয়া উচিত। এমএসডিএন ডক্স এখানে । প্রথম উদাহরণ:

SELECT Top (20) *
FROM Northwind..Orders TABLESAMPLE(20 PERCENT)
ORDER BY NEWID()

টেবিলের নমুনার পিছনে ধারণাটি হ'ল আপনি যা জিজ্ঞাসা করেছেন তার প্রায় সাবসেট আকার দেওয়া। এসকিউএল প্রতিটি ডেটা পৃষ্ঠাতে নম্বর দেয় এবং সেই পৃষ্ঠাগুলির X শতাংশ নির্বাচন করে se নির্বাচিত পৃষ্ঠাগুলিতে যা বিদ্যমান রয়েছে তার ভিত্তিতে আপনি ফিরে আসার আসল সংখ্যাটি পরিবর্তিত হতে পারে।

তাহলে আমি কীভাবে এটি ব্যবহার করব? এমন একটি সাবসেট আকার নির্বাচন করুন যা আপনার প্রয়োজনীয় সারিগুলির চেয়ে বেশি কভার করবে, তারপরে একটি যুক্ত করুন Top()। ধারণাটি হল আপনি ব্যয়বহুল বাছাইয়ের আগে আপনার জিনরমাস টেবিলটিকে আরও ছোট করে তুলতে পারেন।

ব্যক্তিগতভাবে আমি এটি ব্যবহার করে আমার টেবিলের আকার সীমাবদ্ধ করতে ব্যবহার করেছি। সুতরাং যে মিলিয়ন সারি টেবিলটিতে top(20)...TABLESAMPLE(20 PERCENT)কোয়েরিটি 1600 মিমিতে 5600 এ নেমে আসে। একটি REPEATABLE()বিকল্প রয়েছে যেখানে আপনি পৃষ্ঠা নির্বাচনের জন্য "বীজ" পাস করতে পারেন। এটির স্থিতিশীল নমুনা নির্বাচনের ফলাফল হওয়া উচিত।

যাইহোক, কেবল ভেবেছি এটিকে আলোচনায় যুক্ত করা উচিত। আশা করি এটি কাউকে সাহায্য করবে।


একটি স্কেলেবল এলোমেলো-অর্ডিং কোয়েরি লিখতে সক্ষম হওয়ায় আপনার পছন্দ হবে যা কেবলমাত্র স্কেল আপ করে না তবে ছোট ডেটা সেটগুলির সাথেও কাজ করে। মনে হচ্ছে আপনার নিজের কাছে TABLESAMPLE()থাকা কতটা ডেটা রয়েছে তার ভিত্তিতে আপনাকে ম্যানুয়ালি স্যুইচ করতে হবে। আমি মনে করি না যে TABLESAMPLE(x ROWS)এটি এমনকি কমপক্ষে x সারিগুলিও ফিরে আসার বিষয়টি নিশ্চিত করবে কারণ নথিভুক্তি বলছে যে "সারিগুলি ফিরে আসল আসল সংখ্যা উল্লেখযোগ্যভাবে পরিবর্তিত হতে পারে। আপনি যদি 5 এর মতো একটি সংখ্যক সংখ্যা নির্দিষ্ট করেন তবে আপনি নমুনায় ফল পাবেন না ”" - তাই ROWSসিনট্যাক্সটি এখনও সত্যিই কেবল একটি মুখোশযুক্ত PERCENT?
বিনকি

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

3

অনেক টেবিলের তুলনামূলকভাবে ঘন (কয়েকটি অনুপস্থিত মান) সূচিকিত সংখ্যাযুক্ত আইডি কলাম থাকে।

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

উদাহরণস্বরূপ, নীচের কোডটি ব্যবহারকারীদের স্ট্যাক ওভারফ্লো সারণী থেকে 100 টি স্বতন্ত্র এলোমেলো ব্যবহারকারী চয়ন করে, যার মধ্যে 8,123,937 টি সারি রয়েছে।

প্রথম পদক্ষেপটি আইডি মানগুলির পরিসীমা নির্ধারণ করে, সূচকের কারণে কার্যকর অপারেশন:

DECLARE 
    @MinID integer,
    @Range integer,
    @Rows bigint = 100;

--- Find the range of values
SELECT
    @MinID = MIN(U.Id),
    @Range = 1 + MAX(U.Id) - MIN(U.Id)
FROM dbo.Users AS U;

ব্যাপ্তি ক্যোয়ারী

পরিকল্পনা সূচকের প্রতিটি প্রান্ত থেকে এক সারি পাঠ করে।

এখন আমরা পরিসীমাটিতে 100 টি পৃথক এলোমেলো আইডি উত্পন্ন করি (ব্যবহারকারীদের সারণীতে সারণির সাথে মিল রেখে) এবং এই সারিগুলি ফিরিয়ে আনি:

WITH Random (ID) AS
(
    -- Find @Rows distinct random user IDs that exist
    SELECT DISTINCT TOP (@Rows)
        Random.ID
    FROM dbo.Users AS U
    CROSS APPLY
    (
        -- Random ID
        VALUES (@MinID + (CONVERT(integer, CRYPT_GEN_RANDOM(4)) % @Range))
    ) AS Random (ID)
    WHERE EXISTS
    (
        SELECT 1
        FROM dbo.Users AS U2
            -- Ensure the row continues to exist
            WITH (REPEATABLEREAD)
        WHERE U2.Id = Random.ID
    )
)
SELECT
    U3.Id,
    U3.DisplayName,
    U3.CreationDate
FROM Random AS R
JOIN dbo.Users AS U3
    ON U3.Id = R.ID
-- QO model hint required to get a non-blocking flow distinct
OPTION (MAXDOP 1, USE HINT ('FORCE_LEGACY_CARDINALITY_ESTIMATION'));

এলোমেলো সারি কোয়েরি

পরিকল্পনাটি দেখায় যে এই ক্ষেত্রে 100 টি মিল থাকা সারিগুলি খুঁজতে 601 এলোমেলো সংখ্যার প্রয়োজন হয়েছিল। এটি বেশ দ্রুত:

সারণী 'ব্যবহারকারী'। স্ক্যান কাউন্ট 1, যৌক্তিক পাঠ 1937, শারীরিক 2 টি, পঠন-পঠন 408 পড়বে
সারণী 'ওয়ার্কটেবল'। স্ক্যান কাউন্ট 0, লজিকাল রিড 0, ফিজিকাল রিড 0, রিড-ফরোডড রিড 0
সারণী 'ওয়ার্কফাইল'। স্ক্যান কাউন্ট 0, লজিকাল রিড 0, ফিজিকাল রিড 0, রিড-ফরোডড রিড 0

 এসকিউএল সার্ভার এক্সিকিউশন টাইমস:
   সিপিইউ সময় = 0 এমএস, অতিবাহিত সময় = 9 এমএস।

স্ট্যাক এক্সচেঞ্জ ডেটা এক্সপ্লোরারে এটি ব্যবহার করে দেখুন।


0

যেমনটি আমি এই নিবন্ধে ব্যাখ্যা করেছি , এসকিউএল ফলাফল সেটটি বদলানোর জন্য আপনাকে একটি ডাটাবেস-নির্দিষ্ট ফাংশন কল ব্যবহার করতে হবে।

নোট করুন যে কোনও র‌্যান্ডম ফাংশনটি ব্যবহার করে একটি বৃহত ফলাফলের সেট বাছাই করা খুব ধীর হয়ে যেতে পারে, তাই এটি নিশ্চিত করুন যে আপনি এটি ছোট ফলাফলের সেটগুলিতে করছেন।

আপনি একটি বড় ফলাফল সেট অদলবদল এবং এটি পরে সীমিত করতে থাকে, তাহলে এটি SQL সার্ভার ব্যবহার করার জন্য ভালো TABLESAMPLEমধ্যে SQL সার্ভার দফার মাধ্যমে অনুক্রমে একটি র্যান্ডম ফাংশনের পরিবর্তে।

সুতরাং, ধরে নিলাম আমাদের কাছে নিম্নলিখিত ডাটাবেস সারণি রয়েছে:

এখানে চিত্র বর্ণনা লিখুন

এবং songসারণীতে নিম্নলিখিত সারিগুলি :

| id | artist                          | title                              |
|----|---------------------------------|------------------------------------|
| 1  | Miyagi & Эндшпиль ft. Рем Дигга | I Got Love                         |
| 2  | HAIM                            | Don't Save Me (Cyril Hahn Remix)   |
| 3  | 2Pac ft. DMX                    | Rise Of A Champion (GalilHD Remix) |
| 4  | Ed Sheeran & Passenger          | No Diggity (Kygo Remix)            |
| 5  | JP Cooper ft. Mali-Koa          | All This Love                      |

এসকিউএল সার্ভারে আপনাকে NEWIDনিম্নলিখিত ফাংশনটি ব্যবহার করতে হবে, যেমন নীচের উদাহরণ দ্বারা চিত্রিত:

SELECT
    CONCAT(CONCAT(artist, ' - '), title) AS song
FROM song
ORDER BY NEWID()

এসকিউএল সার্ভারে পূর্বোক্ত এসকিউএল কোয়েরিটি চলাকালীন, আমরা নিম্নলিখিত ফলাফল সেটটি পেতে যাচ্ছি:

| song                                              |
|---------------------------------------------------|
| Miyagi & Эндшпиль ft. Рем Дигга - I Got Love      |
| JP Cooper ft. Mali-Koa - All This Love            |
| HAIM - Don't Save Me (Cyril Hahn Remix)           |
| Ed Sheeran & Passenger - No Diggity (Kygo Remix)  |
| 2Pac ft. DMX - Rise Of A Champion (GalilHD Remix) |

লক্ষ্য করুন যে গানগুলি এলোমেলোভাবে ক্রমে তালিকাভুক্ত করা হচ্ছে, NEWIDঅর্ডার বাই ক্লজ দ্বারা ব্যবহৃত ফাংশন কলকে ধন্যবাদ ।

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