2012-06-22 5 views
5

Dato questo:mysql partizionamento con UNIX_TIMESTAMP da variabile

delimiter // 
create procedure setup() 
begin 
    declare d datetime; 
    set d = rounddate(now()); 

    create table s_time (req_id int not null, 
         ser_id int not null, 
         hel_id int not null, 
         posted int unsigned not null, 
         completed int unsigned not null default 0 
        ) 
    partition by range (completed) (partition p0 values less than (unix_timestamp(d)), 
            partition p1 values less than (unix_timestamp(d + interval 1 day)) 
           ); 
end// 

ottengo:

ERROR 1064 (42000) : Constant, random, or timezone-dependent expression in (sub)partitioning function are not allowed

Esiste un modo per ottenere questo lavoro, o devo usare un hard- stringa codificata per l'input. vale a dire: unix_timestamp('2012-07-07 00:00:00')

+0

Il tuo tavolo 's_time' dovrebbe sopravvivere alla fine della procedura? Inoltre, ti aspetti che le partizioni vengano riorganizzate in modo automatico? In altre parole: adesso, la partizione 'p0' contiene tutti i record fino a ora. Tra 24 ore da adesso, ci si aspetta che 'p0' contenga tutti i record fino a" in 24 ore da ora "? – RandomSeed

+0

Questa procedura serve solo per impostare automaticamente la tabella. La tabella verrà utilizzata come partizione mobile. Dopo 24 ore la prima partizione verrà eliminata e ne verrà aggiunta un'altra. Mi chiedevo se fosse possibile non codificare le due prime partizioni. Immagino che potrei fare un'altra procedura che fa i primi due tiri iniziali e chiamare quella dopo la creazione della tabella con valori hardcoded. –

risposta

5

Per mantenere la soluzione in pieno sql questo è quello che ho trovato.

delimiter // 
create procedure setup() 
begin 
    declare d, d2 int; 
    set d = unix_timestamp(); 
    set d2 = unix_timestamp(now() + interval 1 day); 

    create table s_time (req_id int not null, 
         ser_id int not null, 
         hel_id int not null, 
         posted int unsigned not null, 
         completed int unsigned not null default 0 
        ); 

    SET @stmt = concat('alter table s_time PARTITION BY RANGE (completed) (
         partition p0 values less than (', d, '), 
         partition p1 values less than (', d2, '))'); 
    PREPARE pStmt FROM @stmt; 
    EXECUTE pStmt; 
    DEALLOCATE PREPARE pStmt; 

end// 
delimiter ; 
call setup(); 
2

Il motivo di questo non funziona non è così chiaro, ho il sospetto di un bug sia nella documentazione o nel messaggio di errore. L'errore che stai ricevendo è inappropriato, secondo me.

Secondo the manual:

I seguenti costrutti non sono ammessi nel partizionamento espressioni:

  • stored procedure, funzioni memorizzate, UDF, o plugin.
  • Variabili dichiarate o variabili utente.

Questo spiega perché la definizione della tabella non riesce.

Ora, come sbarazzarsi della variabile? Se si tenta di rimuovere la variabile dichiarata dalla definizione della partizione:

CREATE TABLE s_time (
    completed INT UNSIGNED NOT NULL DEFAULT 0 
) 
PARTITION BY RANGE (completed ) (
    PARTITION p0 VALUES LESS THAN (UNIX_TIMESTAMP()) 
); 

si otterrà lo stesso errore. Tuttavia, gli stati MySQL manual:

È anche possibile utilizzare un'espressione in VALORI MENO DI clausole. Tuttavia, MySQL deve essere in grado di valutare il valore restituito dell'espressione come parte di un confronto inferiore a (<).

Secondo questa definizione, UNIX_TIMESTAMP() dovrebbe essere un'espressione valida. Questa frase dal manuale è inaccurata per non dire altro. Sono molto curioso di vedere se qualcun altro potrebbe fornire un'altra comprensione.

Ora, guardando il messaggio di errore, se si considera la clausola LESS THAN come una parte della "funzione di partizionamento", quindi il messaggio di errore comincia ad avere senso:

ERROR 1064 (42000): Costante, casuale o fuso orario-dipendente espressione in (sub) partizionamento funzione o in meno di clausola non sono ammessi

per "random", significano anche non deterministico, che la funzione UNIX_TIMESTAMP() è per definizione.

Per ottenere ciò che si sta tentando di fare, non vedo altra soluzione che utilizzare uno script esterno per generare il comando ALTER TABLE appropriato.

1) Create la vostra tabella iniziale:

CREATE TABLE s_time (
    req_id INT NOT NULL, 
    ser_id INT NOT NULL, 
    hel_id INT NOT NULL, 
    posted INT UNSIGNED NOT NULL, 
    completed INT UNSIGNED NOT NULL DEFAULT 0 
) PARTITION BY RANGE (completed) (
    PARTITION p0 VALUES LESS THAN (0), 
    PARTITION p1 VALUES LESS THAN (1) 
); 

2) Reorganise the partitions di tanto in tanto (per esempio con PHP):

<?php 
    $query = 
     "ALTER TABLE s_time REORGANIZE PARTITION p0, p1 INTO (
      PARTITION p0 VALUES LESS THAN ($today), 
      PARTITION p1 VALUES LESS THAN ($tomorrow) 
     )"; 

Vedere le proof of concept here.