it-swarm.asia

MySQL - أسرع طريقة لتغيير الطاولة لـ InnoDB

لدي جدول InnoDB أريد تغييره. يحتوي الجدول على ما يقرب من 80 مليون صف ، وترك بعض المؤشرات.

أريد تغيير اسم أحد الأعمدة وإضافة بعض المؤشرات الإضافية.

  • ما هي أسرع طريقة للقيام بذلك (بافتراض أنني قد أعاني حتى من وقت التوقف - الخادم خادم غير مستخدم)؟
  • هو "سهل" alter table الحل الأسرع؟

في هذا الوقت ، كل ما يهمني هو السرعة :)

12
Ran

إحدى الطرق المؤكدة لتسريع ALTER TABLE هي إزالة الفهارس غير الضرورية

فيما يلي الخطوات الأولية لتحميل نسخة جديدة من الجدول

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
;

يرجى ملاحظة ما يلي:

  • أسقطت source_persona_index لأنه العمود الأول في 4 فهارس أخرى

    • unique_target_persona
    • unique_target_object
    • source_and_target_object_index
    • source_target_persona_index
  • لقد أسقطت target_persona_index لأنه العمود الأول في فهرسين آخرين

    • target_persona_relation_type_index
    • target_persona_relation_type_message_id_index
  • لقد أسقطت target_persona_relation_type_index لأن العمودين الأولين موجودان أيضًا في target_persona_relation_type_message_id_index

حسنا هذا يعتني بالفهارس غير الضرورية. هل هناك أي مؤشرات ذات أصالة منخفضة؟ إليك طريقة تحديد ذلك:

قم بتشغيل الاستعلامات التالية:

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 صف. كقاعدة عامة ، لن يستخدم مُحسِّن استعلام MySQL فهرسًا إذا كانت أصالة الأعمدة المحددة أكبر من 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;

هذا كل شيء ، صحيح؟ لا !!!

إذا كان موقعك على الويب قيد التشغيل طوال الوقت ، فقد يكون هناك INSERTs تعمل ضد s_relations أثناء تحميل s_relations_new. كيف يمكنك استرداد تلك الصفوف المفقودة؟

اذهب ابحث عن الحد الأقصى للمعرف في s_relations_new وأضف كل شيء بعد ذلك المعرف من s_relations. للتأكد من تجميد الجدول واستخدامه فقط لهذا التحديث ، يجب أن يكون لديك القليل من وقت التعطل من أجل الحصول على تلك الصفوف الأخيرة التي تم إدراجها في s_relation_new. إليك ما تفعله:

في نظام التشغيل ، أعد تشغيل mysql حتى لا يتمكن أي شخص آخر من تسجيل الدخول ولكن root @ localhost (يعطل TCP/IP):

$ 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;

ثم أعد تشغيل الخلية بشكل طبيعي

$ service mysql restart

الآن ، إذا لم تتمكن من حذف mysql لأسفل ، فسيتعين عليك القيام بالطعم والتبديل على s_relations. فقط قم بتسجيل الدخول إلى mysql وقم بما يلي:

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;
14
RolandoMySQLDBA

تعتمد الإجابة الصحيحة على إصدار محرك MySQL الذي تستخدمه.

في حالة استخدام 5.6+ ، يتم إجراء عمليات إعادة التسمية وإضافة/إزالة المؤشرات عبر الإنترنت ، أي دون نسخ جميع بيانات الجدول.

فقط استخدم ALTER TABLE كالمعتاد ، ستكون فورية في الغالب لعمليات إعادة التسمية وإسقاط الفهرس ، وسريعة بشكل معقول لإضافة الفهرس (بسرعة قراءة كل الجدول مرة واحدة).

إذا كنت تستخدم الإصدار 5.1+ ، وتم تمكين المكون الإضافي InnoDB ، فستكون إضافة/إزالة المؤشرات عبر الإنترنت أيضًا. لست متأكدا من إعادة تسمية.

إذا كنت تستخدم إصدارًا أقدم ، ALTER TABLE لا يزال الأسرع — ولكن من المحتمل أن يكون بطيئًا بشكل رهيب لأنه جميع بياناتك = سيتم إعادة إدراجه في جدول مؤقت تحت غطاء المحرك.

أخيرًا ، حان وقت فضح الأسطورة. لسوء الحظ ليس لدي ما يكفي من الكارما هنا للتعليق على الإجابات ، لكني أشعر أنه من المهم تصحيح الإجابة الأكثر تصويتًا. هذا خطأ :

كقاعدة عامة ، لن يستخدم مُحسِّن استعلام MySQL فهرسًا إذا كانت أصالة الأعمدة المحددة أكبر من 5٪ من عدد صفوف الجدول

انها في الواقع العكس .

تفيد المؤشرات في تحديد قليل الصفوف ، لذلك من المهم أن يكون لها high أصالة ، مما يعني العديد من القيم المميزة وعددًا قليلًا من الصفوف إحصائيًا بنفس القيمة.

12
mezis

لقد واجهت نفس المشكلة مع Maria DB 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/

2
Saule

لإعادة تسمية العمود ،

ALTER TABLE tablename CHANGE columnname newcolumnname datatype;

يجب أن يكون على ما يرام ولا يحمل أي فترة توقف.

بالنسبة إلى الفهارس ، ستقوم عبارة CREATE INDEX بقفل الجدول. إذا كان عبدًا غير مستخدم كما ذكرت ، فهذا ليس مشكلة.

أحد الخيارات الأخرى هو إنشاء جدول جديد تمامًا يحتوي على أسماء الأعمدة والفهارس المناسبة. ثم يمكنك نسخ جميع البيانات إليها ، ثم تنفيذ سلسلة

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

سيؤدي ذلك إلى تقليل وقت التوقف عن العمل على حساب استخدام ضعف المساحة مؤقتًا.

0
TetonSig

لدي هذه المشكلة أيضًا واستخدمت SQL:

/*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;   

آمل أن يساعد شخص ما

مع تحياتي،

إرادة

0
William Rossier