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


12

আমার একটি InnoDB টেবিল রয়েছে যা আমি পরিবর্তন করতে চাই। টেবিলটিতে M 80M সারি রয়েছে এবং কয়েকটি সূচক ছাড়ুন।

আমি একটি কলামের নাম পরিবর্তন করতে এবং আরও কয়েকটি সূচক যুক্ত করতে চাই।

  • এটি করার দ্রুততম উপায় কোনটি (ধরে নিলাম আমি ডাউনটাইম এমনকি ভোগ করতে পারি - সার্ভারটি একটি অব্যবহৃত গোলাম)?
  • একটি "সমতল" alter table, দ্রুততম সমাধান?

এই মুহুর্তে, আমি যা যত্ন করি তা হ'ল গতি :)


দয়া SHOW CREATE TABLE tblname\Gকরে কলামটি পরিবর্তন করা দরকার, কলামের ডেটাটাইপ এবং কলামটির নতুন নামটি দেখান।
রোল্যান্ডোমাইএসকিউএলডিবিএ

এটি এখানে: pastie.org/3078349 কলামটির নাম পরিবর্তন করতে হবে sent_atএবং এটি আরও কয়েকটি সূচক যুক্ত করতে হবে
রান করুন

প্রেরণ_এর নামকরণ কী দরকার?
রোল্যান্ডোমাইএসকিউএলডিবিএ

new_sent_at: দেয় বলে
Ran

উত্তর:


14

অলটার টেবিলে গতি বাড়ানোর একটি নিশ্চিত উপায় হ'ল অপ্রয়োজনীয় সূচকগুলি সরিয়ে ফেলা

টেবিলের একটি নতুন সংস্করণ লোড করার প্রাথমিক পদক্ষেপ এখানে

CREATE TABLE s_relations_new LIKE s_relations;
#
# Drop Duplicate Indexes
#
ALTER TABLE s_relations_new
    DROP INDEX source_persona_index,
    DROP INDEX target_persona_index,
    DROP INDEX target_persona_relation_type_index
;

নিম্নলিখিত নোট করুন:

  • আমি উত্স_পারসোনা_আইডেক্সকে বাদ দিয়েছি কারণ এটি অন্যান্য 4 সূচকের প্রথম কলাম

    • unique_target_persona
    • unique_target_object
    • source_and_target_object_index
    • source_target_persona_index
  • আমি টার্গেট_পারসোনা_আইডেক্সকে বাদ দিয়েছি কারণ এটি অন্যান্য 2 সূচকের প্রথম কলাম

    • target_persona_relation_type_index
    • target_persona_relation_type_message_id_index
  • আমি টার্গেট_পারসোনা_ রিলেশন_ টাইপ_আইডেক্সকে বাদ দিয়েছি কারণ প্রথম 2 টি কলামগুলিও টার্গেট_পারসোনা_ রিলেশন_ টাইপ_মেসেজ_আইডি_আইডেক্সে রয়েছে

ঠিক আছে এটি অপ্রয়োজনীয় সূচকের যত্ন নেয়। এমন কোনও সূচক রয়েছে যার কার্ডিনালিটি কম? এটি নির্ধারণের জন্য এখানে উপায়:

নিম্নলিখিত প্রশ্নগুলি চালান:

SELECT COUNT(DISTINCT sent_at)               FROM s_relations;
SELECT COUNT(DISTINCT message_id)            FROM s_relations;
SELECT COUNT(DISTINCT target_object_id)      FROM s_relations;

আপনার প্রশ্ন অনুসারে প্রায় 80,000,000 সারি রয়েছে। থাম্বের নিয়ম হিসাবে, নির্বাচিত কলামগুলির কার্ডিনালিটি টেবিলের সারি গণনার 5% এর চেয়ে বেশি হলে মাইএসকিউএল কোয়েরি অপ্টিমাইজার কোনও সূচক ব্যবহার করবে না। এই ক্ষেত্রে, এটি 4,000,000 হবে।

  • যদি COUNT(DISTINCT sent_at)> 4,000,000
    • তারপর ALTER TABLE s_relations_new DROP INDEX sent_at_index;
  • যদি COUNT(DISTINCT message_id)> 4,000,000
    • তারপর ALTER TABLE s_relations_new DROP INDEX message_id_index;
  • যদি COUNT(DISTINCT target_object_id)> 4,000,000
    • তারপর ALTER TABLE s_relations_new DROP INDEX target_object_index;

একবারে সেই সূচকগুলির কার্যকারিতা বা অকেজোতা নির্ধারণ করা হলে আপনি ডেটা পুনরায় লোড করতে পারেন

#
# Change the Column Name
# Load the Table
#
ALTER TABLE s_relations_new CHANGE sent_at sent_at_new int(11) DEFAULT NULL;
INSERT INTO s_relations_new SELECT * FROM s_relations;

ঠিক তাই না? না !!!

যদি আপনার ওয়েবসাইটটি এই পুরো সময়টি অবধি থাকে তবে s_references_ নতুন লোড করার সময় s_re ਸੰਬੰਧগুলির বিরুদ্ধে INSERTs চলতে পারে। আপনি কীভাবে এই নিখোঁজ সারিগুলি পুনরুদ্ধার করতে পারেন?

S_references_ নতুন মধ্যে সর্বাধিক আইডি সন্ধান করুন এবং s_references থেকে সেই আইডির পরে সমস্ত কিছু যুক্ত করুন। টেবিলটি হিমশীতল এবং কেবলমাত্র এই আপডেটের জন্য ব্যবহৃত হয়েছে তা নিশ্চিত করার জন্য, আপনাকে s_relation_new thoseোকানো হয়েছে এমন শেষ সারিগুলি পাওয়ার জন্য আপনার অবশ্যই কিছুটা ডাউনটাইম করতে হবে। এখানে কি কি:

ওএসে, মাইএসকিএল পুনরায় চালু করুন যাতে অন্য কেউ লগইন করতে না পারে তবে রুট @ লোকালহোস্ট (টিসিপি / আইপি অক্ষম করে):

$ service mysql restart --skip-networking

এরপরে, mysql এ লগইন করুন এবং সেই শেষ সারিগুলি লোড করুন:

mysql> SELECT MAX(id) INTO @maxidnew FROM s_relations_new;
mysql> INSERT INTO s_relations_new SELECT * FROM s_relations WHERE id > @maxidnew;
mysql> ALTER TABLE s_relations RENAME s_relations_old;
mysql> ALTER TABLE s_relations_new RENAME s_relations;

তারপরে, সাধারণত mysql পুনরায় আরম্ভ করুন

$ service mysql restart

এখন, আপনি যদি মাইএসকিএল নামাতে না পারেন, আপনাকে s_references উপর একটি টোপ এবং স্যুইচ করতে হবে। কেবল মাইএসকিএল-এ লগইন করুন এবং নিম্নলিখিতগুলি করুন:

mysql> ALTER TABLE s_relations RENAME s_relations_old;
mysql> SELECT MAX(id) INTO @maxidnew FROM s_relations_new;
mysql> INSERT INTO s_relations_new SELECT * FROM s_relations_old WHERE id > @maxidnew;
mysql> ALTER TABLE s_relations_new RENAME s_relations;

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

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

mysql> DROP TABLE s_relations_old;

12

সঠিক উত্তরটি আপনি যে মাইএসকিউএল ইঞ্জিনটি ব্যবহার করছেন তার সংস্করণটির উপর নির্ভর করে।

যদি 5.6+ ব্যবহার করা হয়, নাম পরিবর্তন করা এবং সূচকগুলি যুক্ত / সরানো অনলাইনে করা হয় , অর্থাত্ সমস্ত টেবিলের ডেটা অনুলিপি না করে।

কেবল ALTER TABLEযথারীতি ব্যবহার করুন , এটি বেশিরভাগ নাম এবং সূচকের ড্রপগুলির জন্য তাত্ক্ষণিক হবে এবং সূচী সংযোজনের জন্য যুক্তিসঙ্গতভাবে দ্রুত হবে (একবারে সমস্ত টেবিল একবার পড়ার মতো দ্রুত)।

যদি 5.1+ ব্যবহার করা হয় এবং InnoDB প্লাগইন সক্ষম করা থাকে তবে সূচকগুলি যুক্ত / অপসারণও অনলাইনে থাকবে। নাম পরিবর্তন সম্পর্কে নিশ্চিত নয়।

যদি পুরানো সংস্করণ ব্যবহার করা ALTER TABLEহয় তবে এটি এখনও দ্রুত — তবে সম্ভবত ভয়াবহভাবে ধীর হবে কারণ আপনার সমস্ত ডেটা হুডের নীচে অস্থায়ী টেবিলটিতে পুনরায় প্রবেশ করা হবে।

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

থাম্বের নিয়ম হিসাবে, নির্বাচিত কলামগুলির কার্ডিনালিটি টেবিলের সারি গণনার 5% এর চেয়ে বেশি হলে মাইএসকিউএল কোয়েরি অপ্টিমাইজার কোনও সূচক ব্যবহার করবে না

এটা আসলে এর অন্যান্য উপায় কাছাকাছি

সূচকগুলি কয়েকটি সারি নির্বাচন করতে কার্যকর , তাই তাদের উচ্চ কার্ডিনালিটি হওয়া গুরুত্বপূর্ণ , যার অর্থ অনেকগুলি স্বতন্ত্র মান এবং একই মান সহ পরিসংখ্যানগতভাবে কয়েকটি সারি।


InnoDB প্লাগইন ডকুমেন্টেশনের লিঙ্ক (সীমাবদ্ধতার কারণে পেস্ট করা যায়নি)।
mezis

2
মাইএসকিউএল 5.5-তে আমি RENAME TABLEতাত্ক্ষণিকভাবে (প্রত্যাশার মতো) পেয়েছি তবে CHANGE COLUMNপ্রাথমিক কীটির নামকরণের জন্য একটি সম্পূর্ণ অনুলিপি করেছে ... 7 ঘন্টা! সম্ভবত এটি প্রাথমিক কী ছিল বলেই? ভাল না.
কেসিডি

2

মারিয়া ডিবি 10.1.12 এর সাথে আমারও একই সমস্যা ছিল, তারপরে ডকুমেন্টেশন পড়ার পরে আমি দেখতে পেলাম যে "অপারেশন" অপারেশন করার একটি বিকল্প আছে যা টেবিলের অনুলিপিটিকে সরিয়ে দেয়। এই বিকল্পের সাহায্যে অ্যাল্টার টেবিলটি খুব দ্রুত। আমার ক্ষেত্রে এটি ছিল:

alter table user add column (resettoken varchar(256),
  resettoken_date date, resettoken_count int), algorithm=inplace;

এটি খুব দ্রুত। অ্যালগরিদম বিকল্প ছাড়া এটি কখনও শেষ হবে না।

https://mariadb.com/kb/en/mariadb/alter-table/


0

কলামটির পুনরায় নামকরণের জন্য,

ALTER TABLE tablename CHANGE columnname newcolumnname datatype;

ভাল থাকতে হবে এবং কোনও ডাউনটাইম বহন করা উচিত নয়।

সূচকের জন্য ক্রেডিট ইন্ডেক্সের বিবৃতিটি সারণিটিকে লক করে দেবে। যদি আপনি উল্লিখিত হিসাবে এটি একটি অব্যবহৃত গোলাম, এটি কোনও সমস্যা নয়।

আর একটি বিকল্প হ'ল এমন একটি ব্র্যান্ড নিউ টেবিল তৈরি করা যাতে যথাযথ কলামের নাম এবং সূচি থাকে। তারপরে আপনি এতে সমস্ত ডেটা অনুলিপি করতে পারেন, তারপরে একটি সিরিজ চালিয়ে যান

BEGIN TRAN;
ALTER TABLE RENAME tablename tablenameold;
ALTER TABLE RENAME newtablename tablename;
DROP TABLE tablenameold;
COMMIT TRAN;

এটি অস্থায়ীভাবে দ্বিগুণ স্থান ব্যবহারের ব্যয়ে ডাউনটাইমকে হ্রাস করবে।


1
মাইএসকিউএল-এ ডিডিএল লেনদেনমূলক নয়। প্রতিটি ডিডিএল বিবৃতি একটি কমিট ট্রিগার করে। আমি এটি সম্পর্কে লিখেছি: dba.stackexchange.com/a/36799/877
RolandoMySQLDBA

0

আমিও এই সমস্যা পেয়েছি এবং আমি এই এসকিউএল ব্যবহার করেছি:

/*on créé la table COPY SANS les nouveaux champs et SANS les FKs */
CREATE TABLE IF NOT EXISTS prestations_copy LIKE prestations;

/* on supprime les FKs de la table actuelle */
ALTER TABLE `prestations`
DROP FOREIGN KEY `fk_prestations_pres_promos`,
DROP FOREIGN KEY `fk_prestations_activites`;

/* on remet les FKs sur la table copy */
ALTER TABLE prestations_copy 
    ADD CONSTRAINT `fk_prestations_activites` FOREIGN KEY (`act_id`) REFERENCES `activites` (`id`) ON UPDATE NO ACTION ON DELETE NO ACTION,
    ADD CONSTRAINT `fk_prestations_pres_promos` FOREIGN KEY (`presp_id`) REFERENCES `pres_promos` (`id`) ON UPDATE NO ACTION ON DELETE NO ACTION;

/* On fait le transfert des données de la table actuelle vers la copy, ATTENTION: il faut le même nombre de colonnes */
INSERT INTO prestations_copy
SELECT * FROM prestations;

/* On modifie notre table copy de la façon que l'on souhaite */
ALTER TABLE `prestations_copy`
    ADD COLUMN `seo_mot_clef` VARCHAR(50) NULL;

/* on supprime la table actuelle et renome la copy avec le bon nom de table */
SET FOREIGN_KEY_CHECKS=0;
DROP TABLE prestations;
RENAME TABLE prestations_copy TO prestations;
SET FOREIGN_KEY_CHECKS=1;   

আমি আশা করি এটি কাউকে সাহায্য করতে পারে

শুভেচ্ছা সহ,

ইচ্ছাশক্তি

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