কোয়েরি পুনরুত্পাদন করার জন্য প্রয়োজনীয় ডাটাবেসের একটি উপসেটটি কি ম্যাককিলডাম্প করা সম্ভব?


37

পটভূমি

আমি selectকোয়েরি পুনরুত্পাদন করার জন্য প্রয়োজনীয় আমার ডাটাবেসের সাবসেট সরবরাহ করতে চাই । আমার লক্ষ্যটি হল আমার গণনার কর্মপ্রবাহকে পুনরায় উত্পাদনযোগ্য করে তোলা ( প্রজননযোগ্য গবেষণার মতো )।

প্রশ্ন

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

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

উদাহরণ

উদাহরণস্বরূপ, আমার বিশ্লেষণ ডেটার একটি উপসেটকে জিজ্ঞাসা করতে পারে যা একাধিক (এই উদাহরণে 3) সারণী থেকে রেকর্ডের প্রয়োজন:

select table1.id, table1.level, table2.name, table2.level 
       from table1 join table2 on table1.id = table2.table1_id 
       join table3 on table3.id = table2.table3_id
       where table3.name in ('fee', 'fi', 'fo', 'fum'); 

ঠিক আছে, সুতরাং কোনও অতিরিক্ত রেকর্ড নেই। আপনি কি কোয়েরি দ্বারা নির্দিষ্ট কলামগুলি চান?
রিচার্ড

@ রিচার্ড আমি এটি বিবেচনা করি নি - এটি কীভাবে করা যায় তা জানতে পেরে ভাল লাগবে।
ডেভিড লেবাউর

3
এটি একটি খুব অনন্য প্রশ্ন যা আমি নিশ্চিত যে কেউ কেউ অবাক হয়েছেন এবং এর উত্তর দেওয়া দরকার। এই ধরণের প্রশ্নটি জনসমক্ষে আনার জন্য +1।
রোল্যান্ডোমাইএসকিউএলডিবিএ

ভবিষ্যতের পাঠকগণ: গৃহীত উত্তর ছাড়াও, র্যান্ডমেক্সের উত্তর দেখুন , যা বিশেষভাবে ক্যোয়ারির দ্বারা প্রয়োজনীয় ডেটা ফেলে দেয়।
টুলমেকারস্টেভ

উত্তর:


52

mysqldump হয়েছে --where একটি প্রদত্ত টেবিল একটি WHERE বাক্যাংশ চালানো বিকল্প।

যদিও যোগদানের ক্যোয়ারিটি মাইসকিल्डম্প করা সম্ভব নয়, আপনি প্রতিটি টেবিল থেকে নির্দিষ্ট সারিগুলি রফতানি করতে পারেন যাতে প্রতিটি টেবিল থেকে প্রাপ্ত প্রতিটি সারি পরবর্তীকালে যোগদানের সাথে যুক্ত হতে পারে।

আপনার প্রদত্ত ক্যোয়ারির জন্য আপনার তিনবার মাইএসকিल्ड্প্প করতে হবে:

প্রথমে, মেসকিल्ड্প্প সমস্ত টেবিল 3 সারি নামের সাথে ('ফি', 'ফাই', 'ফো', 'ফম'):

mysqldump -u... -p... --where="name in ('fee','fi','fo','fum')" mydb table3 > table3.sql

এরপরে, mysqldump সমস্ত টেবিল 2 সারি যেখানে প্রথম mysqldump এর সাথে table3_id মানের সাথে মিল রয়েছে:

mysqldump -u... -p... --lock-all-tables --where="table3_id in (select id from table3 where name in ('fee','fi','fo','fum'))" mydb table2 > table2.sql

তারপরে, mysqldump সমস্ত টেবিল 1 সারি যা দ্বিতীয় mysqldump থেকে টেবিল 1_id মানগুলির সাথে মেলে:

mysqldump -u... -p... --lock-all-tables --where="id in (select table1_id from table2 where table3_id in (select id from table3 where name in ('fee','fi','fo','fum')))" mydb table1 > table1.sql

দ্রষ্টব্য: যেহেতু দ্বিতীয় এবং তৃতীয় মাইএসকিল্ডাম্পগুলির জন্য একাধিক টেবিল ব্যবহার করা দরকার, - লক-অল-টেবিলগুলি অবশ্যই ব্যবহার করা উচিত

আপনার নতুন ডাটাবেস তৈরি করুন:

mysqladmin -u... -p... mysqladmin create newdb

শেষ অবধি, তিনটি মাইএসকিলডাম্পকে অন্য একটি ডাটাবেসে লোড করুন এবং সেখানে নতুন ডাটাবেসে যোগদানের চেষ্টা করুন।

mysql -u... -p... -D newdb < table1.sql
mysql -u... -p... -D newdb < table2.sql
mysql -u... -p... -D newdb < table3.sql

মাইএসকিএল ক্লায়েন্টে আপনার যোগদানের ক্যোয়ারী চালান

mysql> use newdb
mysql> select table1.id, table1.level, table2.name, table2.level 
       from table1 join table2 on table1.id = table2.table1_id 
       join table3 on table3.id = table2.table3_id
       where table3.name in ('fee', 'fi', 'fo', 'fum'); 

একবার চেষ্টা করে দেখো !!!

সতর্কতা: সঠিকভাবে সূচকযুক্ত না করা হলে, দ্বিতীয় এবং তৃতীয় মাইএসকিলডাম্প চিরতরে নিতে পারে !!!

সেক্ষেত্রে নিম্নলিখিত কলামগুলিকে সূচী করুন:

ALTER TABLE table2 ADD INDEX (table1_id);
ALTER TABLE table2 ADD INDEX (table3_id);
ALTER TABLE table3 ADD INDEX (name,id);

আমি ধরে নেব আইডিটি টেবিল 3 এর প্রাথমিক কী।


1
বিস্তারিত উদাহরণের জন্য ধন্যবাদ! আমি --whereনথিতে দফাটি মিস করেছি ; আমার চেষ্টা করার সুযোগ পাওয়ার পরে কীভাবে এটি কাজ করে তা আপনাকে জানাতে দেবে।
ডেভিড লেবাউর

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

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

@ রোল্যান্ডো আপনার সহায়তার জন্য ধন্যবাদ এটি পুরোপুরি কাজ করেছে
ডেভিড লেবাউর

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

7

আমি এই সমস্যাটি সমাধান করার জন্য মাইএসকিএলডাম্পের পরিবর্তে আপনার নির্বাচনের অংশ হিসাবে একটি ' আউটফিল ' ব্যবহার করার বিষয়টি বিবেচনা করব । আপনি যা যা নির্বাচন নির্বাচন করতে পারেন তা নির্ধারণ করতে পারেন, তারপরে সিএসভি শৈলীর আউটপুট জন্য উপযুক্ত কনফিগারেশন সহ শেষে "INTO OUTFILE '/path/to/outfile.csv' ..." যুক্ত করুন। তারপরে আপনি ডেটা আপনার নতুন স্কিমা অবস্থানে লোড করতে কেবল ' লোড ডেটা ইনফিল ...' সিনট্যাক্সের মতো কিছু ব্যবহার করতে পারেন ।

উদাহরণস্বরূপ, আপনার এসকিউএল ব্যবহার:

select table1.id, table1.level, table2.name, table2.level 
       from table1 join table2 on table1.id = table2.table1_id 
       join table3 on table3.id = table2.table3_id
       where table3.name in ('fee', 'fi', 'fo', 'fum')
INTO OUTFILE '/tmp/fee-fi-fo-fum.csv'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
; 

মনে রাখবেন আপনার লক্ষ্য ডিস্ক পার্টিশনে পর্যাপ্ত স্টোরেজ স্পেসের প্রয়োজন হবে।


আমি ড্যাটালোডের জন্য এটি পছন্দ করি। আপনার এখনও নতুন ডাটাবেসে স্কিমাটি পেতে হবে তবে এটি অন্য কয়েকটি কৌশল ব্যবহার করে সহজেই অর্জন করা যেতে পারে।
রিচার্ড

আমি এটিও পছন্দ করি কারণ কিছু লোক বেস টেবিলগুলি নাও চায়, কেবলমাত্র সিএসভি আমদানি করা হিসাবে যুক্ত ফলাফল। +1 !!!
রোল্যান্ডোমাইএসকিউএলডিবিএ

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

ভবিষ্যতের পাঠকদের জন্য ডেভিডের মন্তব্য পুনরায়: যেমন রিচার্ড উল্লেখ করেছেন, আপনাকে আলাদাভাবে যুক্ত টেবিলগুলির স্কিমা রফতানি করতে হবে । এই স্কিমগুলি সহজেই একটি নতুন ডাটাবেসে লোড করা যায়। তারপরে, র্যান্ডমেক্স যেমন বলেছে, আপনি Load Data Infileসেই নতুন ডাটাবেসে সেই .csv লোড করতে ব্যবহার করবেন। এখন, ক্যোয়ারী কার্যকর করা যেতে পারে।
টুলমেকারস্টেভ

আমি কেবল বুঝতে পেরেছি যে এই কৌশলটির সীমাবদ্ধতাটি হ'ল ক্যোয়ারী আউটপুটটি মূল সারণীর মতো প্রতিষ্ঠানে নয় in যদিও আমি এখনও এই পদ্ধতির পছন্দ করি না কেন, মূল টেবিলের কাঠামোটি পুনরায় তৈরি করতে: সেই টেবিলের জন্য প্রয়োজনীয় ডেটা রফতানি করার জন্য আলাদা আলাদা ক্যোরিয়াম চালান table
স্টিভ

6

Mysqldump ব্যবহারের একটি --tables বিকল্প রয়েছে যা আপনাকে কোন টেবিলগুলি ডাম্প করতে হবে তা নির্দিষ্ট করতে দেয়। এটি আপনাকে সারণির তালিকা নির্দিষ্ট করতে দেয়।

আমি কোনও সহজ (স্বয়ংক্রিয়) উপায় জানি না।


আপনার সহায়তার জন্য আপনাকে ধন্যবাদ, তবে আমি কেবল প্রতিটি টেবিলের নির্বাচিত সারিগুলি কেবলমাত্র প্রয়োজনীয় টেবিলগুলিই রফতানি করতে চাই। আমি একটি স্ক্রিপ্ট দিয়ে ডাম্প অনুসরণ থাকতে পারে delete from table1 where id not in (.....);যে যদি সবচেয়ে সহজ উপায়, যতদিন স্ক্রিপ্ট, যাবে স্বয়ংক্রিয়, এটা যে নির্দিষ্ট টুল থাকে প্রয়োজন নেই।
ডেভিড লেবাউর

আপনি একটি +1 প্রাপ্য কারণ - টেবিলগুলি সহজতর হবে এবং অপ্রয়োজনীয় ডেটা ফেলে দেওয়া নতুন সার্ভারে আরও বেশি ঘোড়ার কাজ হবে, বিশেষত যদি জড়িত টেবিলগুলি প্রতিটি 1GB এর বেশি থাকে। বেশিরভাগ লোকেরা সেভাবে এটি করে একটি বৃহত্তর স্তরের স্বাচ্ছন্দ্য বোধ করবে কারণ পদক্ষেপের ক্ষেত্রে এটি কেবল অর্থবোধ করে। আমার উত্তরটি একটু পরিকল্পনা এবং কিছুটা বেশি ঝুঁকি নিয়েছে।
RolandoMySQLDBA


2

আপনি কি মাইএসকিএলে কোট ফাংশনটি ব্যবহার করে দেখেছেন?

SELECT CONCAT("insert into table4(id,level,name,levelt2) VALUES(",   quote(table1.id),   ",",    quote(table1.level),   ",",    quote(table2.name),   ",",    quote(table2.level),    ");") as q
       from table1 join table2 on table1.id = table2.table1_id 
       join table3 on table3.id = table2.table3_id
       where table3.name in ('fee', 'fi', 'fo', 'fum'); 

উপরোক্তভাবে সংরক্ষণ করুন, ক্যোয়ারী.এসকিউএল হিসাবে

cat query.sql|mysql --skip-column-names --raw > table4.sql

1

মাইএসকিউএল এ:

SHOW CREATE TABLE table1; -- use these two create statements
SHOW CREATE TABLE table2; -- to design table4's create statement
CREATE TABLE table4( .... );
INSERT INTO table4(id,level,name,levelt2)
SELECT table1.id, table1.level, table2.name, table2.level 
   from table1 join table2 on table1.id = table2.table1_id 
   join table3 on table3.id = table2.table3_id
   where table3.name in ('fee', 'fi', 'fo', 'fum'); 

কমান্ড লাইনে:

mysqldump mydb table4 |gzip > table4.sql.gz

আপনার গন্তব্য সার্ভারে, up / .my.cnf সেটআপ করুন

[client]
default-character-set=utf8

গন্তব্য সার্ভারে আমদানি

zcat table4.sql.gz | mysql

1

অনুরূপ সমস্যার জন্য আমি একটি ছোট স্ক্রিপ্ট লিখেছি, এটি এখানে: https://github.com/digitalist/mysql_slice

include ('queryDumper.php');


$exampleQuery="select * from information_schema.columns c1 
left join information_schema.columns c2 on 1=1 limit 1";

//define credentials
$exampleMysqli = new mysqli($host, $user, $password, $database);
$exampleResult=$exampleMysqli->query($exampleQuery);

//if  mysqlnd (native driver installed), otherwise use wrapper
$exampleData=fetchAll($exampleResult);
$exampleMeta=$exampleResult->fetch_fields();

/*
 * field content removal options
 * column name => function name in queryDumper.php, namespace QueryDumperHelpers
 * 
 * */

$forbiddenFields=array(
'password'=>'replacePassword', //change password -> md5("password")
'login'=>'replaceLogin', //change login vasya@mail.ru -> vasya@example.com
'comment'=>'sanitizeComment' //lorem ipsum or 
);


//get tables dump
$dump=(\queryDumper\dump($exampleData, $exampleMeta, $forbiddenFields));



$dropDatabase=true; //default false
$dropTable=true; //default false

$dbAndTablesCreationDump=\QueryDumperDatabaseAndTables\dump($exampleMysqli,$exampleMeta, $dropDatabase, $dropTable);

$databases=$dbAndTablesCreationDump['databases'];
$tables=$dbAndTablesCreationDump['tables'];
$eol=";\n\n";
echo implode($eol, $databases)."\n";
echo implode($eol, $tables).";\n";
echo "\n";

//consider using array_unique($dump) before imploding
echo implode("\n\n", $dump);
echo "\n";
?>

অর্থাৎ আপনার এই প্রশ্নটি রয়েছে :

SELECT * FROM employees.employees e1 
LEFT JOIN employees.employees e2 ON 1=1 
LIMIT 1; 

আপনি এই ডাম্প পেয়েছেন :

DROP DATABASE `employees`;

CREATE DATABASE `employees`;
CREATE TABLE `employees` ( /* creation code */ ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT IGNORE INTO `employees`.`employees` VALUES ("10001","1953-09-02","Georgi","Facello","M","1986-06-26");

INSERT IGNORE INTO `employees`.`employees` VALUES ("10001","1953-09-02","Georgi","Facello","M","1986-06-26");
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.