2009-11-23 10 views
12

मैं एक मेज हो रही है कुछ इस तरह देखने से नया विभाजन बनाया जा सकता:MySQL घटना अनुसूचक

CREATE TABLE `Calls` (
    `calendar_id` int(11) NOT NULL, 
    `db_date` timestamp NOT NULL, 
    `cgn` varchar(32) DEFAULT NULL, 
    `cpn` varchar(32) DEFAULT NULL, 
    PRIMARY KEY (`calendar_id`), 
    KEY `db_date_idx` (`db_date`) 
) 
PARTITION BY RANGE (calendar_id)(
    PARTITION p20091024 VALUES LESS THAN (20091024) , 
    PARTITION p20091025 VALUES LESS THAN (20091025)); 

मैं किसी भी तरह स्वचालित रूप से एक नया विभाजन जोड़ने के लिए (2 दिन पहले ही) mysql अनुसूचक उपयोग कर सकते हैं - मैं एक उदाहरण है की हर दिन एक नया विभाजन जोड़ना होगा की तलाश में हूँ - यह

alter table Calls add partition (partition p20091026 values less than(20091026)); 

कहाँ p20091026/20,091,026 निर्माण किया है की तरह कुछ चलाने था जब निर्धारित कार्य चलाने के लिए, अब +2 दिन से मूल्य पाने । (या क्या मैं क्रॉन के माध्यम से इसे स्क्रिप्ट करने के बेहतर हूं?)

+1

एक साथ निष्पादन की रोकथाम में 1024 विभाजन तालिका के अनुसार अनुमति की एक अधिकतम कर रहे हैं, तो यह समाधान 3 वर्ष से कम में विभाजन से बाहर चला जाएगा। और जिन मामलों में दैनिक विभाजन प्रदर्शन में सुधार करेंगे, वे बहुत दुर्लभ होने जा रहे हैं ... यदि आप वास्तव में ऐसा करने का आग्रह करते हैं, तो आपको हर दिन एक नया विभाजन बनाने की आवश्यकता नहीं है, [यहां] देखें (http://stackoverflow.com/ए/6163679/238419) –

उत्तर

28

हां, आप यह कर सकते हैं।

ध्यान दें कि शेड्यूलर डिफ़ॉल्ट रूप से सक्रिय नहीं है (Event Scheduler Configuration देखें), इसलिए यह शून्य-जोखिम विकल्प नहीं है। उदाहरण के लिए, यदि आपकी ऑपरेशंस टीम आपके ऐप को नए सर्वर पर माइग्रेट करती है, लेकिन शेड्यूलर को सक्षम करना भूल जाती है, तो आपका ऐप हो जाएगा। विशेष विशेषाधिकारों की भी आवश्यकता है, जिसे फिर से एक नए सर्वर पर स्थापित करने की आवश्यकता हो सकती है।

मेरी सलाह: सबसे पहले, एक संग्रहित प्रक्रिया बनाएं (नीचे कोड नमूना देखें) जो आवधिक विभाजन रखरखाव को संभालती है: यदि तालिका बहुत बड़ी हो जाती है, और पर्याप्त नए विभाजन (जैसे 1 सप्ताह) जोड़ना पुराना विभाजन छोड़ना ताकि यहां तक ​​कि यदि रखरखाव proc थोड़ी देर के लिए नहीं चल रहा है, आपका ऐप मर नहीं जाएगा।

फिर उस संग्रहित प्रो को अनावश्यक रूप से कॉल शेड्यूल करें। MySQL शेड्यूलर का उपयोग करें, क्रॉन जॉब का उपयोग करें, और अपनी पसंद के किसी अन्य तरीके का उपयोग करें। फिर यदि एक शेड्यूलर काम नहीं कर रहा है, तो दूसरा ढीला उठा सकता है। यदि आप सही ढंग से स्पोक को डिज़ाइन करते हैं, तो इसे नो-ऑप निष्पादित करने के लिए सस्ता होना चाहिए यदि उसे कुछ भी करने की आवश्यकता नहीं है। आप इसे अपने ऐप से भी कॉल करना चाहते हैं, उदा। लंबी अवधि की रिपोर्ट उत्पन्न करते समय, या अपनी दैनिक ईटीएल प्रक्रिया (यदि आपके पास कोई है) के हिस्से के रूप में पहला बयान के रूप में। मेरा मुद्दा यह है कि अनुसूचित कार्यों की एचिलिस एड़ी यह सुनिश्चित कर रही है कि शेड्यूलर वास्तव में काम कर रहा है - इसलिए यहां अनावश्यकता के बारे में सोचें।

बस सुनिश्चित करें कि सभी कॉल एक ही समय में शेड्यूल न करें ताकि वे एक-दूसरे पर कदम न उठाएं! :-)

यहां आपकी रखरखाव प्रसंस्करण की तरह दिखने के लिए एक कोड नमूना है - पहले यह पुराने विभाजन को prunes करता है, फिर नए जोड़ता है। मैंने पाठक के लिए एक निष्कर्ष के रूप में एकाधिक एक साथ निष्पादन की जांच और रोकथाम छोड़ दिया।

DELIMITER $$ 

DROP PROCEDURE IF EXISTS `test`.`UpdatePartitions` $$ 
CREATE PROCEDURE `test`.`UpdatePartitions`() 
BEGIN 

    DECLARE maxpart_date date; 
    DECLARE partition_count int; 
    DECLARE minpart date; 
    DECLARE droppart_sql date; 
    DECLARE newpart_date date; 
    DECLARE newpart_sql varchar(500); 

    SELECT COUNT(*) 
    INTO partition_count 
    FROM INFORMATION_SCHEMA.PARTITIONS 
    WHERE TABLE_NAME='Calls' AND TABLE_SCHEMA='test'; 

    -- first, deal with pruning old partitions 
    -- TODO: set your desired # of partitions below, or make it parameterizable 
    WHILE (partition_count > 1000) 
    DO 

    -- optionally, do something here to deal with the parition you're dropping, e.g. 
    -- copy the data into an archive table 

    SELECT MIN(PARTITION_DESCRIPTION) 
     INTO minpart 
     FROM INFORMATION_SCHEMA.PARTITIONS 
     WHERE TABLE_NAME='Calls' AND TABLE_SCHEMA='test'; 

    SET @sql := CONCAT('ALTER TABLE Calls DROP PARTITION p' 
         , CAST((minpart+0) as char(8)) 
         , ';'); 

    PREPARE stmt FROM @sql; 
    EXECUTE stmt; 
    DEALLOCATE PREPARE stmt; 

    SELECT COUNT(*) 
     INTO partition_count 
     FROM INFORMATION_SCHEMA.PARTITIONS 
     WHERE TABLE_NAME='Calls' AND TABLE_SCHEMA='test'; 


    END WHILE; 

    SELECT MAX(PARTITION_DESCRIPTION) 
    INTO maxpart_date 
    FROM INFORMATION_SCHEMA.PARTITIONS 
    WHERE TABLE_NAME='Calls' AND TABLE_SCHEMA='test'; 

    -- create enough partitions for at least the next week 
    WHILE (maxpart_date < CURDATE() + INTERVAL 7 DAY) 
    DO 

    SET newpart_date := maxpart_date + INTERVAL 1 DAY; 
    SET @sql := CONCAT('ALTER TABLE Calls ADD PARTITION (PARTITION p' 
         , CAST((newpart_date+0) as char(8)) 
         , ' values less than(' 
         , CAST((newpart_date+0) as char(8)) 
         , '));'); 

    PREPARE stmt FROM @sql; 
    EXECUTE stmt; 
    DEALLOCATE PREPARE stmt; 

    SELECT MAX(PARTITION_DESCRIPTION) 
     INTO maxpart_date 
     FROM INFORMATION_SCHEMA.PARTITIONS 
     WHERE TABLE_NAME='Calls' AND TABLE_SCHEMA='test'; 

    END WHILE; 

END $$ 

DELIMITER ; 

Btw, विभाजन रखरखाव (नया विभाजन सुनिश्चित पहले से बनाई गई हैं, पुराने विभाजन प्रूनिंग, आदि) है, IMHO, गंभीर रूप से महत्वपूर्ण स्वचालित करने के लिए। मैंने व्यक्तिगत रूप से एक बड़े उद्यम डेटा वेयरहाउस को एक दिन के लिए नीचे देखा है क्योंकि एक साल के लायक विभाजनों को शुरुआत में cretaed किया गया था, लेकिन अगले वर्ष आने के बाद कोई भी अधिक विभाजन बनाने के लिए याद नहीं आया। तो यह बहुत अच्छा है कि आप स्वचालन के बारे में सोच रहे हैं - यह उस परियोजना के लिए अच्छा है जो आप काम कर रहे हैं। :-)

+0

तालिका को बदलने पर, आप परिभाषित नहीं कर रहे हैं कि कौन सा विभाजन संशोधित करना है या कुछ याद आ रहा है। उदाहरण के लिए यह कैसे पता चलता है कि विभाजन को 'calender_Id' में जोड़ रहा है या यह है कि आप केवल एक प्रकार का विभाजन कर सकते हैं और क्योंकि विभाजन पहले से ही बनाया गया है, यह' calender_id' –

+0

@shahmir पर डिफ़ॉल्ट है - उपरोक्त कोड ' विभाजन को संशोधित नहीं कर रहा है, यह एक पुराना विभाजन छोड़ रहा है और एक नया जोड़ रहा है। प्रति टेबल केवल एक विभाजन योजना है। मूल पोस्टर का प्रश्न दिखाता है कि विभाजन कैलेंडर_आईडी पर होता है। –

8

जस्टिन से उत्कृष्ट समाधान। मैंने अपना कोड अपने वर्तमान प्रोजेक्ट के शुरुआती बिंदु के रूप में लिया और कुछ चीजों का उल्लेख करना चाहूंगा जो मैं इसे कार्यान्वित कर रहा था।

  1. तालिका आपको MAXVALUE प्रकार विभाजन शामिल नहीं होना चाहिए पर इस चलाने में मौजूदा विभाजन संरचना - सभी विभाजनों शाब्दिक दिनांक द्वारा सीमांकित किया जाना चाहिए। ऐसा इसलिए है क्योंकि चयन MAX (PARTITION_DESCRIPTION) 'MAXVALUE' वापस कर देगा जो अगले चरण में किसी दिनांक में परिवर्तित होने में विफल रहता है। यदि आपको कुछ कहने पर प्रक्रिया को कॉल करते समय अजीब संदेश मिलता है: '<' के लिए collations का अवैध मिश्रण, यह समस्या हो सकती है।

  2. यह एक अच्छा विचार है: "AND TABLE_SCHEMA = 'dbname'" INFORMATION_SCHEMA तालिका से विभाजन नामों का चयन करते समय, क्योंकि एक से अधिक विभाजन एक ही तालिका के लिए एक ही नाम के साथ मौजूद हो सकते हैं (विभिन्न डेटाबेस में) , वे सभी INFORMATION_SCHEMA तालिका में एक साथ सूचीबद्ध हैं। TABLE_SCHEMA विनिर्देश के बिना आपके चयन उदा। MAX (PARTITION_DESCRIPTION) आपको प्रत्येक डेटाबेस में उस नाम के सारणी के लिए प्रत्येक मौजूदा विभाजन के बीच अधिकतम विभाजन नाम देगा।

  3. कहीं भी जिस तरह से मुझे ऑल्टर टेबल xxx एडीडी पार्टिशन के साथ समस्या थी क्योंकि यह जस्टिन के समाधान में है, मुझे लगता है कि विभाजन नाम (yyyymmdd) के लिए एक ही प्रारूप विभाजन विभाजन के रूप में उपयोग किया जा रहा था yyyy-mm-dd (v5.6.2)।

  4. डिफ़ॉल्ट व्यवहार केवल भविष्य में आवश्यक विभाजन को जोड़ना है। यदि आप अतीत के लिए विभाजन बनाना चाहते हैं, तो आपको पहले सबसे पुराने विभाजन की तुलना में पुरानी तारीख के लिए विभाजन सेट अप करना होगा। उदाहरण के लिए। यदि आप पिछले 30 दिनों से डेटा रखते हैं, तो पहले 35 दिनों पहले कहने के लिए विभाजन जोड़ें और फिर प्रक्रिया चलाएं। अनुमोदित, यह केवल खाली तालिका पर ऐसा करने के लिए संभव हो सकता है, लेकिन मैंने सोचा कि यह उल्लेखनीय है।

  5. 4 में पिछले/भविष्य के विभाजन की वांछित अवधि बनाने के लिए आपको शुरुआत में प्रक्रिया को दो बार चलाने की आवश्यकता होगी। उपर्युक्त उदाहरण 4 के लिए, पहला रन -35 दिनों के लिए विभाजन, और आवश्यक भविष्य विभाजन के लिए विभाजन बनाएगा। दूसरा रन तब -35 और -30 के बीच विभाजन को ट्रिम करेगा।

इस समय मैं इसका उपयोग कर रहा हूं। मैंने कॉलर के दृष्टिकोण से थोड़ा अधिक लचीला बनाने के लिए कुछ पैरामीटर जोड़े। आप डेटाबेस, तालिका, वर्तमान दिनांक, और पिछले और भविष्य दोनों के लिए कितने विभाजन रखना चाहते हैं।

मैं भी विभाजन के नामकरण बदल इतना है कि विभाजन p20110527 नामित दिन का प्रतिनिधित्व करता है 2011/05/27 से 00:00 दिन उस समय समाप्त होने के बजाय शुरू।

वहाँ अभी भी कोई त्रुटि जाँच या :-)

DELIMITER $$ 

DROP PROCEDURE IF EXISTS UpdatePartitions $$ 

-- Procedure to delete old partitions and create new ones based on a given date. 
-- partitions older than (today_date - days_past) will be dropped 
-- enough new partitions will be made to cover until (today_date + days_future) 
CREATE PROCEDURE UpdatePartitions (dbname TEXT, tblname TEXT, today_date DATE, days_past INT, days_future INT) 
BEGIN 

DECLARE maxpart_date date; 
DECLARE partition_count int; 
DECLARE minpart date; 
DECLARE droppart_sql date; 
DECLARE newpart_date date; 
DECLARE newpart_sql varchar(500); 

SELECT COUNT(*) 
INTO partition_count 
FROM INFORMATION_SCHEMA.PARTITIONS 
WHERE TABLE_NAME=tblname 
AND TABLE_SCHEMA=dbname; 

-- SELECT partition_count; 

-- first, deal with pruning old partitions 
WHILE (partition_count > days_past + days_future) 
DO 
-- optionally, do something here to deal with the parition you're dropping, e.g. 
-- copy the data into an archive table 

SELECT STR_TO_DATE(MIN(PARTITION_DESCRIPTION), '''%Y-%m-%d''') 
    INTO minpart 
    FROM INFORMATION_SCHEMA.PARTITIONS 
    WHERE TABLE_NAME=tblname 
    AND TABLE_SCHEMA=dbname; 

-- SELECT minpart; 

SET @sql := CONCAT('ALTER TABLE ' 
        , tblname 
        , ' DROP PARTITION p' 
        , CAST(((minpart - INTERVAL 1 DAY)+0) as char(8)) 
        , ';'); 

-- SELECT @sql; 
PREPARE stmt FROM @sql; 
EXECUTE stmt; 
DEALLOCATE PREPARE stmt; 

SELECT COUNT(*) 
    INTO partition_count 
    FROM INFORMATION_SCHEMA.PARTITIONS 
    WHERE TABLE_NAME=tblname 
    AND TABLE_SCHEMA=dbname; 

-- SELECT partition_count; 

END WHILE; 

SELECT STR_TO_DATE(MAX(PARTITION_DESCRIPTION), '''%Y-%m-%d''') 
INTO maxpart_date 
FROM INFORMATION_SCHEMA.PARTITIONS 
WHERE TABLE_NAME=tblname 
AND TABLE_SCHEMA=dbname; 

-- select maxpart_date; 
-- create enough partitions for at least the next days_future days 
WHILE (maxpart_date < today_date + INTERVAL days_future DAY) 
DO 

-- select 'here1'; 
SET newpart_date := maxpart_date + INTERVAL 1 DAY; 
SET @sql := CONCAT('ALTER TABLE ' 
        , tblname 
        , ' ADD PARTITION (PARTITION p' 
        , CAST(((newpart_date - INTERVAL 1 DAY)+0) as char(8)) 
        , ' VALUES LESS THAN (''' 
        , newpart_date 
        , '''));'); 

-- SELECT @sql; 
PREPARE stmt FROM @sql; 
EXECUTE stmt; 
DEALLOCATE PREPARE stmt; 

SELECT STR_TO_DATE(MAX(PARTITION_DESCRIPTION), '''%Y-%m-%d''') 
    INTO maxpart_date 
    FROM INFORMATION_SCHEMA.PARTITIONS 
    WHERE TABLE_NAME=tblname 
    AND TABLE_SCHEMA=dbname; 

SET maxpart_date := newpart_date; 

END WHILE; 

END $$ 

DELIMITER ;