মানগুলির একটি সেট থেকে, আমি কীভাবে সারণির কলামে মানগুলি সন্ধান না করব?


12

আমার কাছে একটি টেবিল রয়েছে যা কয়েক লক্ষ সংখ্যক পূর্ণসংখ্যার সম্ভাব্য পরিমাণে সঞ্চয় করবে

desc id_key_table;

+----------------+--------------+------+-----+---------+-------+
| Field          | Type         | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+-------+
| id_key         | int(16)      | NO   | PRI | NULL    |       |
+----------------+--------------+------+-----+---------+-------+

একটি প্রোগ্রাম থেকে, আমি পূর্ণসংখ্যার একটি বড় সেট আছে। আমি দেখতে চাই যে এর মধ্যে কোনটি পূর্ণসংখ্যার উপরের id_key কলামে নেই।

এখনও অবধি আমি নিম্নলিখিত পন্থাগুলি নিয়ে এসেছি:

1) প্রতিটি পূর্ণসংখ্যার মাধ্যমে Iterate এবং একটি সঞ্চালন:

select count(*) count from id_key_table where id_key = :id_key

গণনা 0 হলে id_keyটি টেবিল থেকে নিখোঁজ হয়।

এটি এটি করার মতো ভয়ঙ্কর, ভয়ঙ্কর উপায় বলে মনে হচ্ছে।


2) একটি অস্থায়ী টেবিল তৈরি করুন, প্রতিটি মান অস্থায়ী টেবিলের মধ্যে সন্নিবেশ করুন এবং দুটি টেবিলের সাথে একটি JOIN সঞ্চালন করুন।

create temporary table id_key_table_temp (id_key int(16) primary key );

insert into id_key_table_temp values (1),(2),(3),...,(500),(501);

select temp.id_key
from id_key_table_temp temp left join id_key_table as main 
         on temp.id_key = main.id_key 
where main.killID is null;

drop table id_key_table_temp;

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

এই ধরণের অনুসন্ধানের জন্য কি সঠিক জিজ্ঞাসা রয়েছে?

(মাইএসকিউএল)


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

স্বাগত জানার জন্য আপনাকে ধন্যবাদ, আমি ভেবেছিলাম স্ট্যাকওভারফ্লোয়ের চেয়ে এর মতো কোনও জায়গায় আরও কিছু গুরু থাকতে পারে। যদিও সেখানে পুনরায় জিজ্ঞাসা করতে আমার আপত্তি নেই।
ক্লিনটন

2
: হিসাবে প্রস্তাব, আমি Stackoverflow করতে পুনরায় পোস্ট stackoverflow.com/questions/5967822/...
ক্লিনটন

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

উত্তর:


7

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


5

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

SELECT * FROM id_key_table_temp 
WHERE id_key NOT IN (select id_key FROM id_key_table);

আমি মাইএসকিউএল প্ল্যাটফর্মের পার্থক্য সম্পর্কে কোনও জ্ঞান না থাকায় আমি একটি নিয়মিত টেবিলের উপর অস্থায়ী টেবিলটির সমর্থন করছি না। ওরাকলে একটি অস্থায়ী টেবিল সম্ভবত সেরা হবে তবে ওরাকলে আপনি কেবল একটি টেবিল হিসাবে একটি অ্যারে ব্যবহার করবেন এবং এটিতে সরাসরি যোগদান করবেন।
লেইফ রিফেল

3

একটি অস্থায়ী টেবিলের পরিবর্তে এবং সন্নিবেশ করানোর পরিবর্তে insert into id_key_table_temp values (1),(2),(3),...,(500),(501);, আপনি যে সমস্ত মান যাচাই করতে চেষ্টা করছেন তা সহ আপনি একটি subquery তৈরি করতে পারেন:

select id_key
from ( select @row := @row + 1 as id_key 
       from (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) s1,
            (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) s2,
            (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) s3,
            (select 0 union all select 1 union all select 3 union all select 4 union all select 5 union all select 6 union all select 6 union all select 7 union all select 8 union all select 9) s4,
            (select @row:=0) s5 ) s
where id_key in(1, 2, 3, 500, 501)
      and id_key not in (select id_key from main);

2

আমার মন্তব্যে উল্লিখিত হিসাবে, এটি সম্ভবত স্ট্যাকওভারফ্লোয়ের পক্ষে আরও উপযুক্ত। তবে, আমি মনে করি যে এই দুটি সমাধানই সেরা নয়:

সমাধান 1 এর জন্য একাধিক সিলেক্ট কলগুলি প্রয়োজন, খুব অদক্ষ

সমাধান 2 আরও ভাল, তবে আমি নিশ্চিত নই যে অনেক মান সন্নিবেশ করানোর ব্যয়টিই সেরা সমাধান।

একটি সম্ভাব্য সমাধান 3 একটি জিজ্ঞাসা করা হবে:

SELECT DISTINCT id_key FROM id_key_table

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


ফলাফলটি খুব বড় হবে বলে আমি এই সমাধানের অনুরাগী নই।
ক্লিনটন

@ ক্লিনটন সত্য, তবে এটি আপনার দ্বিতীয় সমাধানেও খুব বড় হতে পারে, যদি আপনি এটি ফিল্টার করার জন্য পর্যাপ্ত পূর্ণসংখ্যার ব্যবস্থা না করেন।
ডেরেক ডউনি

2

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

ইন Stackoverflow , আমি সঞ্চিত পদ্ধতি test.CreateSampleTable এবং test.GetMissingIntegers একটি নমুনা টেবিল তৈরী এবং তারপর বড় করছেন পার্থক্য খুঁজে JOIN সামনে নিয়ে আসতে 'একটি গতিশীল টেম্প সারণি তৈরি ছিল।

এবার, আসুন স্থায়ী টেবিল টেবিলের সাথে নমুনা সারণী তৈরি করি।

এখানে পরীক্ষা রয়েছে L লোডসেম্পলটিবলগুলি:

DELIMITER $$

DROP PROCEDURE IF EXISTS `LoadSampleTables` $$
CREATE DEFINER=`lwdba`@`127.0.0.1` PROCEDURE `LoadSampleTables`(maxinttoload INT)
BEGIN

  DECLARE X,OKTOUSE,MAXLOOP INT;

  DROP TABLE IF EXISTS test.id_key_table;
  DROP TABLE IF EXISTS test.id_key_table_keys;
  CREATE TABLE test.id_key_table (id_key INT(16)) ENGINE=MyISAM;
  CREATE TABLE test.id_key_table_keys (id_key INT(16)) ENGINE=MyISAM;

  SET X=1;
  WHILE X <= maxinttoload DO
    INSERT INTO test.id_key_table VALUES (X);
    SET X = X + 1;
  END WHILE;
  ALTER TABLE test.id_key_table ADD PRIMARY KEY (id_key);

  SET MAXLOOP = FLOOR(SQRT(maxinttoload));
  SET X = 2;
  WHILE X <= MAXLOOP DO
    DELETE FROM test.id_key_table WHERE MOD(id_key,X) = 0 AND id_key > X;
    SELECT MIN(id_key) INTO OKTOUSE FROM test.id_key_table WHERE id_key > X;
    SET X = OKTOUSE;
  END WHILE;
  OPTIMIZE TABLE test.id_key_table;

  INSERT INTO test.id_key_table_keys SELECT id_key FROM test.id_key_table;
  ALTER TABLE test.id_key_table_keys ADD PRIMARY KEY (id_key);
  OPTIMIZE TABLE test.id_key_table_keys;

END $$

DELIMITER ;

এটি চালানোর পরে, এখানে টেবিলগুলি এবং তাদের সামগ্রীগুলি রয়েছে:

mysql> call test.loadsampletables(25);
+-------------------+----------+----------+----------+
| Table             | Op       | Msg_type | Msg_text |
+-------------------+----------+----------+----------+
| test.id_key_table | optimize | status   | OK       |
+-------------------+----------+----------+----------+
1 row in set (0.20 sec)

+------------------------+----------+----------+----------+
| Table                  | Op       | Msg_type | Msg_text |
+------------------------+----------+----------+----------+
| test.id_key_table_keys | optimize | status   | OK       |
+------------------------+----------+----------+----------+
1 row in set (0.28 sec)

Query OK, 0 rows affected (0.29 sec)

mysql> select * from test.id_key_table;
+--------+
| id_key |
+--------+
|      1 |
|      2 |
|      3 |
|      5 |
|      7 |
|     11 |
|     13 |
|     17 |
|     19 |
|     23 |
+--------+
10 rows in set (0.00 sec)

mysql> select * from test.id_key_table_keys;
+--------+
| id_key |
+--------+
|      1 |
|      2 |
|      3 |
|      5 |
|      7 |
|     11 |
|     13 |
|     17 |
|     19 |
|     23 |
+--------+
10 rows in set (0.00 sec)

পার্মটেম্প টেবিলের জন্য এখানে ট্রিগার রয়েছে

mysql> DELIMITER $$
mysql>
mysql> CREATE TRIGGER test.AddPermTempKey AFTER INSERT ON test.id_key_table
    -> FOR EACH ROW
    -> BEGIN
    ->     INSERT IGNORE INTO test.id_key_table_keys VALUES (NEW.id_key);
    -> END $$
Query OK, 0 rows affected (0.09 sec)

mysql>
mysql> CREATE TRIGGER test.DeletePermTempKey AFTER DELETE ON test.id_key_table
    -> FOR EACH ROW
    -> BEGIN
    ->     DELETE FROM test.id_key_table_keys WHERE id_key = OLD.id_key;
    -> END $$
Query OK, 0 rows affected (0.08 sec)

mysql>
mysql> DELIMITER ;

এখন, রেকর্ডগুলির একটি নতুন ব্যাচ আমদানি করা যাক, টেবিল পরীক্ষা we উইক্লি_বাচ, এর আগে ব্যবহৃত কিছু কীগুলি, অন্যান্য কীগুলি ব্র্যান্ডটি নতুন চমকানো:

mysql> CREATE TABLE test.weekly_batch (id_key INT(16)) ENGINE=MyISAM;
Query OK, 0 rows affected (0.04 sec)

mysql> INSERT INTO test.weekly_batch VALUES (17),(19),(23),(29),(31),(37),(41);
Query OK, 7 rows affected (0.00 sec)
Records: 7  Duplicates: 0  Warnings: 0

mysql> ALTER TABLE test.weekly_batch ADD PRIMARY KEY (id_key);
Query OK, 7 rows affected (0.08 sec)
Records: 7  Duplicates: 0  Warnings: 0

আসুন পরীক্ষা করুন। উইকেলি_বাচে এবং নিরাপদে এটিকে টেস্ট.আইড_কি_ টেবিল_কিগুলিতে একীভূত করুন এবং টেবিল পরীক্ষাটি ফর্ম করুন ne নতুন_কিজ_ টো_লোড:

DELIMITER $$

DROP PROCEDURE IF EXISTS `test`.`ImportWeeklyBatch` $$
CREATE PROCEDURE `test`.`ImportWeeklyBatch` ()
TheStoredProcedure:BEGIN

  DECLARE RCOUNT INT;

  SELECT COUNT(1) INTO RCOUNT FROM information_schema.tables
  WHERE table_schema='test' AND table_name='weekly_batch';
  IF RCOUNT = 0 THEN
    LEAVE TheStoredProcedure;
  END IF;
  SELECT COUNT(1) INTO RCOUNT FROM test.weekly_batch;
  IF RCOUNT = 0 THEN
    LEAVE TheStoredProcedure;
  END IF;
  DROP TABLE IF EXISTS test.new_keys_to_load;
  CREATE TABLE test.new_keys_to_load (id_key INT(16));
  INSERT INTO test.new_keys_to_load (id_key)
  SELECT id_key FROM test.weekly_batch A
  LEFT JOIN test.id_key_table_keys B USING (id_key)
  WHERE B.id_key IS NULL;

  SELECT * FROM test.new_keys_to_load;

END $$

DELIMITER ;

ফলাফল এখানে:

mysql> call test.importweeklybatch;
+--------+
| id_key |
+--------+
|     29 |
|     31 |
|     37 |
|     41 |
+--------+
4 rows in set (0.14 sec)

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


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