মাইএসকিউএল "IN" অপারেটরের কার্যকারিতা (বৃহত্তর?) সংখ্যার মানগুলিতে


94

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

আমি ভাবছিলাম যে IN অপারেটরের ভিতরে আইডি এর একটি বৃহত সংখ্যক (300-3000) তালিকাবদ্ধ করা কতটা পারফরম্যান্ট , যা এরকম কিছু দেখবে:

SELECT id, name, price
FROM products
WHERE id IN (1, 2, 3, 4, ...... 3000)

কোনও পণ্য এবং বিভাগের টেবিলের মতো সহজ কিছু কল্পনা করুন যা আপনি সাধারণত কোনও নির্দিষ্ট বিভাগ থেকে পণ্যগুলি পেতে একসাথে যোগদান করতে পারেন । উপরের উদাহরণে আপনি দেখতে পারেন যে রেডিসে প্রদত্ত বিভাগের অধীনে ( ) আমি আইডি 4 সহ বিভাগ থেকে সমস্ত পণ্য আইডিকে ফিরিয়ে দেব এবং সেগুলি অপারেটরের অভ্যন্তরে উপরের ক্যোয়ারিতে রাখি ।category:4:product_idsSELECTIN

এটি কতটা পারফরম্যান্ট?

এটি কি "এটি নির্ভর করে" পরিস্থিতি? বা একটি কংক্রিট "এটি (আন) গ্রহণযোগ্য" বা "দ্রুত" বা "ধীর" আছে বা আমার একটি যুক্ত করা উচিত LIMIT 25, বা সে সাহায্য করে না?

SELECT id, name, price
FROM products
WHERE id IN (1, 2, 3, 4, ...... 3000)
LIMIT 25

অথবা আমি রেডিসের দ্বারা প্রদত্ত প্রোডাক্ট আইডিটির অ্যারেটি ছাঁটাই করে 25 টি সীমাবদ্ধ করে কেবল 3000 এর চেয়ে 25 আইডি যুক্ত করা উচিত এবং কোয়েরির LIMITভিতরে থেকে 25-এ করা উচিত?

SELECT id, name, price
FROM products
WHERE id IN (1, 2, 3, 4, ...... 25)

কোন পরামর্শ / প্রতিক্রিয়া অনেক প্রশংসা করা হয়!


আমি নিশ্চিত না আপনি ঠিক কী জিজ্ঞাসা করছেন? "আইডি আইএন (1,2,3, ... 3000))" সহ একটি ক্যোয়ারী "আইডি = মান" সহ 3000 প্রশ্নের চেয়ে দ্রুত। তবে "ক্যাটাগরি = 4" এর সাথে একটি যোগদান উপরের উভয়ের চেয়ে দ্রুত হবে।
রোনিস

ঠিক আছে, যেহেতু কোনও পণ্য একাধিক বিভাগের অন্তর্ভুক্ত তবে আপনি "বিভাগ = 4" করতে পারবেন না। রেডিস ব্যবহার করে আমি নির্দিষ্ট বিভাগে অন্তর্ভুক্ত এমন সমস্ত পণ্যের আইডি সংরক্ষণ করব এবং তারপরে সেটিকে জিজ্ঞাসা করব। আমি আসল প্রশ্নটি অনুমান করি যে, id IN (1,2,3 ... 3000)জিন টেবিলের তুলনায় পারফরম্যান্সটি কেমন হবে products_categories। নাকি আপনি যা বলছিলেন তা কি?
মাইকেল ভ্যান রুইজেন

শুধু মাইএসকিউএল যে বাগ থেকে সতর্কতা অবলম্বন করা আবশ্যক stackoverflow.com/questions/3417074/...
Itay Moav -Malimovka

অবশ্যই এটি সূচকযুক্ত সারিগুলি পুনরুদ্ধার করার অন্যান্য পদ্ধতির মতো দক্ষ না হওয়ার কোনও কারণ নেই; এটি কেবল ডাটাবেস লেখকরা এটির জন্য পরীক্ষা করেছেন এবং অনুকূলিত করেছেন কিনা তা নির্ভর করে। গণনাগত জটিলতার ক্ষেত্রে আমরা ক্লজটির উপর সবচেয়ে খারাপভাবে একটি O (n লগ এন) বাছাই করতে যাচ্ছি ( INএটি অ্যালগরিদমের উপর নির্ভর করে আপনি দেখানো মত সাজানো তালিকায় লিনিয়ারও হতে পারে), এবং তারপরে লিনিয়ার ছেদ / লুকস্ ।
jberryman

উত্তর:


40

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

যদি নম্বরগুলি একটি ঘন সেট হয় (কোনও ফাঁক নেই - যা নমুনা ডেটার পরামর্শ দেয়), তবে আপনি আরও ভাল করে এটি করতে পারেন WHERE id BETWEEN 300 AND 3000

যাইহোক, সম্ভবত সেটটিতে ফাঁক রয়েছে, যার পরে সর্বোপরি বৈধ মানগুলির তালিকার সাথে চলে যাওয়া ভাল (ফাঁকগুলি অপেক্ষাকৃত সংখ্যায় কম না হলে, আপনি যে ক্ষেত্রে ব্যবহার করতে পারেন)

WHERE id BETWEEN 300 AND 3000 AND id NOT BETWEEN 742 AND 836

বা ফাঁক যাই হোক না কেন।


46
আপনি কি "একটি যোগদান ব্যবহার করুন, একটি অস্থায়ী টেবিল তৈরি করছেন" এর উদাহরণ দিতে পারেন?
জেক

যদি ডেটা সেটটি একটি ইন্টারফেস (বহু-নির্বাচন উপাদান) থেকে আসে এবং নির্বাচিত ডেটাগুলিতে ফাঁক থাকে এবং এই ফাঁকগুলি অনুক্রমিক ফাঁক না হয় (অনুপস্থিত: 457, 490, 658, ..) তবে কার্যকর AND id NOT BETWEEN XXX AND XXXহবে না এবং এটি আরও ভাল (x = 1 OR x = 2 OR x = 3 ... OR x = 99)@ ডেভিড ফেলস যেমন লিখেছেন তেমন সমতুল্য থাকুন।
ডিপসেল

আমার অভিজ্ঞতায় - ই-বাণিজ্য ওয়েবসাইটগুলিতে কাজ করে, আমাদের ~ 50 সম্পর্কিত না থাকা আইডির অনুসন্ধান ফলাফলগুলি দেখাতে হবে, "1.50 আলাদা প্রশ্ন", বনাম "সহ ভাল ফলাফল পেয়েছি" "আইএন-তে অনেক মান সহ একটি প্রশ্ন ধারা ""। এই মুহুর্তের জন্য এটি প্রমাণ করার মতো আমার কোনও উপায় নেই, কেবলমাত্র # 2 কোয়েরিটি আমাদের মনিটরিং সিস্টেমে সর্বদা একটি ধীর ক্যোয়ারী হিসাবে প্রদর্শিত হবে, যেখানে মৃত্যুদণ্ড কার্যকর হওয়ার পরিমাণ নির্বিশেষে # 1 কখনই প্রদর্শিত হবে না লক্ষ লক্ষ ... কারও কি একই অভিজ্ঞতা আছে? (আমরা সম্ভবত এটি আরও ভাল ক্যাচিংয়ের সাথে সম্পর্কিত করতে পারি, বা অন্যান্য প্রশ্নগুলিকে প্রশ্নের মধ্যে স্থান দেওয়ার অনুমতি দিতে পারি ...)
চেইম ক্লার

24

আমি কিছু পরীক্ষা করে যাচ্ছি, এবং ডেভিড ফেলস তার উত্তরে যেমন বলেছেন , এটি বেশ ভালভাবেই অনুকূলিত হয়েছে। একটি রেফারেন্স হিসাবে, আমি 1,000,000 রেজিস্টার সহ একটি ইনোডিবি টেবিল তৈরি করেছি এবং 500,000 এলোমেলো সংখ্যার সাথে "IN" অপারেটরের সাথে একটি নির্বাচন করছি, এটি আমার ম্যাকের জন্য মাত্র 2.5 সেকেন্ড সময় নেয়; কেবল সমান নিবন্ধগুলি নির্বাচন করতে 0.5 সেকেন্ড সময় লাগে।

আমার একটাই সমস্যা ছিল যে আমাকে ফাইল max_allowed_packetথেকে প্যারামিটার বাড়াতে হয়েছিল my.cnf। যদি তা না হয় তবে একটি রহস্যজনক "MYSQL চলে গেছে" ত্রুটি উত্পন্ন হয়েছে।

আমি এই পরীক্ষার জন্য পিএইচপি কোড ব্যবহার করি:

$NROWS =1000000;
$SELECTED = 50;
$NROWSINSERT =15000;

$dsn="mysql:host=localhost;port=8889;dbname=testschema";
$pdo = new PDO($dsn, "root", "root");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$pdo->exec("drop table if exists `uniclau`.`testtable`");
$pdo->exec("CREATE  TABLE `testtable` (
        `id` INT NOT NULL ,
        `text` VARCHAR(45) NULL ,
        PRIMARY KEY (`id`) )");

$before = microtime(true);

$Values='';
$SelValues='(';
$c=0;
for ($i=0; $i<$NROWS; $i++) {
    $r = rand(0,99);
    if ($c>0) $Values .= ",";
    $Values .= "( $i , 'This is value $i and r= $r')";
    if ($r<$SELECTED) {
        if ($SelValues!="(") $SelValues .= ",";
        $SelValues .= $i;
    }
    $c++;

    if (($c==100)||(($i==$NROWS-1)&&($c>0))) {
        $pdo->exec("INSERT INTO `testtable` VALUES $Values");
        $Values = "";
        $c=0;
    }
}
$SelValues .=')';
echo "<br>";


$after = microtime(true);
echo "Insert execution time =" . ($after-$before) . "s<br>";

$before = microtime(true);  
$sql = "SELECT count(*) FROM `testtable` WHERE id IN $SelValues";
$result = $pdo->prepare($sql);  
$after = microtime(true);
echo "Prepare execution time =" . ($after-$before) . "s<br>";

$before = microtime(true);

$result->execute();
$c = $result->fetchColumn();

$after = microtime(true);
echo "Random selection = $c Time execution time =" . ($after-$before) . "s<br>";



$before = microtime(true);

$sql = "SELECT count(*) FROM `testtable` WHERE id %2 = 1";
$result = $pdo->prepare($sql);
$result->execute();
$c = $result->fetchColumn();

$after = microtime(true);
echo "Pairs = $c Exdcution time=" . ($after-$before) . "s<br>";

এবং ফলাফল:

Insert execution time =35.2927210331s
Prepare execution time =0.0161771774292s
Random selection = 499102 Time execution time =2.40285992622s
Pairs = 500000 Exdcution time=0.465420007706s

অন্যের পক্ষে, আমি যুক্ত করতে পারি যে ভার্চুয়ালবক্সে (সেন্টোস) আমার লেট 2013 এমবিপি-তে আই 7 দিয়ে, আউটপুটটির তৃতীয় লাইন (প্রশ্নের সাথে প্রাসঙ্গিক একটি) ছিল: এলোমেলো নির্বাচন = 500744 সময় নির্বাহের সময় = 53.458173036575s .. আপনার আবেদনের উপর নির্ভর করে 53 সেকেন্ড সহনীয় হতে পারে। আমার ব্যবহারের জন্য, সত্যিই না। এছাড়াও, নোট করুন যে %সমান সংখ্যার জন্য পরীক্ষাটি এই প্রশ্নটির জন্য প্রাসঙ্গিক নয় কারণ এটি =পরিবর্তনের পরিবর্তে সমান অপারেটর ( ) সহ মডুলো অপারেটর ( ) ব্যবহার করে IN()
রিনোগো

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

14

আপনি একটি অস্থায়ী টেবিল তৈরি করতে পারেন যেখানে আপনি যে কোনও সংখ্যক আইডি রাখতে এবং নেস্টেড কোয়েরি চালাতে পারেন উদাহরণ:

CREATE [TEMPORARY] TABLE tmp_IDs (`ID` INT NOT NULL,PRIMARY KEY (`ID`));

এবং নির্বাচন করুন:

SELECT id, name, price
FROM products
WHERE id IN (SELECT ID FROM tmp_IDs);

6
সাবকিউরি ব্যবহার না করে আপনার টেম্প টেবিলটিতে যোগদান করা ভাল
scharette

4
@ লুপকিন আপনি কীভাবে ব্যাখ্যা করতে পারেন আপনি কীভাবে একটি বনাম বনাম একটি সাবকোয়ারি দিয়ে এটি করবেন?
জেফ সলোমন 21

4
@ জেফসোলোমন SELECT product.id, নাম, দাম থেকে পণ্যগুলি td__IDs product.id = tmp_IDs.ID এ যোগ দিন;
scharette

এই উত্তর! আমি যা খুঁজছিলাম, দীর্ঘ নিবন্ধগুলির জন্য খুব দ্রুত
দামিান রাফায়েল লাটেনেরো

আপনাকে অনেক ধন্যবাদ, মানুষ। এটি কেবল অবিশ্বাস্যভাবে দ্রুত কাজ করে।
mrHalfer

4

INরেকর্ডগুলির একটি বৃহত তালিকায় একটি বড় পরামিতি সেট সহ ব্যবহার করা আসলে ধীর হবে।

আমি সম্প্রতি যে সমস্যার সমাধান করেছি সে ক্ষেত্রে আমার দুটি দফা ছিল, একটিতে ২,৫০ প্যারামিটার এবং অন্যটি ৩,৫০০ পরামিতি সহ, ৪০ মিলিয়ন রেকর্ডের একটি সারণী জিজ্ঞাসা করছে।

আমার জিজ্ঞাসাটি স্ট্যান্ডার্ডটি ব্যবহার করে 5 মিনিট সময় নিয়েছিল WHERE INআইএন স্টেটমেন্টের জন্য সাবকিউরিটি ব্যবহার না করে (প্যারামিটারগুলি তাদের নিজস্ব ইনডেক্সড টেবিলের মধ্যে রেখে), আমি কোয়েরিটি দুটি সেকেন্ডে পেয়েছি।

আমার অভিজ্ঞতায় মাইএসকিউএল এবং ওরাকল উভয়ের পক্ষে কাজ করেছেন।


4
আমি "আইএন স্টেটমেন্টের জন্য সাবকিউরিটি ব্যবহার না করে (প্যারামিটারগুলিকে তাদের নিজস্ব ইনডেক্সড টেবিলের মধ্যে রেখে)" এ আপনার বক্তব্যটি পাইনি। আপনার অর্থ কি "WHERE ID IN (1,2,3)" ব্যবহার করার পরিবর্তে আমাদের "WHERE ID IN (SEX id from FROM xX)" ব্যবহার করা উচিত?
ইসতিয়াক দর্জি

4

INভাল, এবং ভাল অনুকূলিতকরণ। নিশ্চিত হয়ে নিন যে আপনি এটি কোনও সূচকযুক্ত ক্ষেত্রে ব্যবহার করেছেন এবং আপনি ভাল আছেন।

এটি কার্যত সমান:

(x = 1 OR x = 2 OR x = 3 ... OR x = 99)

যতদূর ডিবি ইঞ্জিন সম্পর্কিত।


4
আসলে তা না. আমি ডিবি থেকে 5 কে রেকর্ড আনতে ক্লাউজ ব্যবহার করি। ইন ক্লাউজে পিকেগুলির তালিকা রয়েছে সুতরাং সম্পর্কিত কলামটি সূচিযুক্ত এবং অনন্য হওয়ার গ্যারান্টিযুক্ত। এক্সপ্ল্লেইন বলেছে যে, "ফিফো-ক্যু-অ্যালাইক" স্টাইলে পিকে লুকআপ ব্যবহারের মাধ্যমে পুরো টেবিল স্ক্যানটি সঞ্চালিত হয়।
আন্তোনিওসেস

মাইএসকিউএলে আমি বিশ্বাস করি না যে তারা "কার্যকরী সমতুল্য"INউন্নত পারফরম্যান্সের জন্য অনুকূলিতকরণ ব্যবহার করে।
জোশুয়া পিন্টার

4
জোশ, উত্তরটি ছিল ২০১১ থেকে - আমি নিশ্চিত যে তখন থেকেই পরিস্থিতি বদলেছে, তবে যেদিন IN ফ্ল্যাট আউট হয়ে গেছে সেগুলি একটি বিবৃতি সিরিজের বা বিবৃতিতে রূপান্তরিত হয়েছিল।
ডেভিড ফেলস

4
এই উত্তরটি সঠিক নয়। থেকে হাই পারফরমেন্স মাইএসকিউএল তাই মাইএসকিউএল মধ্যে, যা () তালিকায় মান বাছাই করে এবং দেখতে কোনো একটি মান তালিকায় রয়েছে ফাস্ট বাইনারি অনুসন্ধান ব্যবহার করে:। এটি তালিকার আকারে ও (লগ এন), যেখানে ওআর ক্লজের একটি সমতুল্য সিরিজ হ'ল ও (এন) তালিকার আকারে (যেমন, বৃহত তালিকার জন্য অনেক ধীর)।
বার্ট

বার্ট - হ্যাঁ এই উত্তর অচল। একটি সম্পাদনা প্রস্তাব নির্দ্বিধায়।
ডেভিড ফেলস

-2

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

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


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