martes, 30 de noviembre de 2010

Tablas particionadas

Si tienes una tabla con varios millones de registros y sabes de antemano que se va a consultar por periodos mensuales, puedes particionar la tabla por años y meses. Así cuando hagas consultas, sólo utilizarás la partición correspondiente y mejorará el rendimiento.

Al particionar por los valores de un determinado campo, es obligatorio tener dicho campo como parte de la primary key de la tabla.

A continuación una migración para crear una tabla particionada por meses y años:

 class CreateHistoryAlerts < ActiveRecord::Migration

  FIRST_YEAR = 2010
  LAST_YEAR  = 2020

  def self.up
    create_table :history_alerts do |t|
      t.integer :agent_id,              :references => nil
      t.integer :alert_type_id,         :references => nil
      t.integer :country_id,            :references => nil
      t.string  :reason
      t.boolean :read

      t.timestamps
    end

    sql = "ALTER TABLE `history_alerts` drop primary key, add primary key(id, created_at)"
    execute(sql);


    sql = "ALTER TABLE `history_alerts` PARTITION BY RANGE (YEAR(created_at)) \
           SUBPARTITION BY HASH (MONTH(created_at)) \
           ("

    for year in (FIRST_YEAR..LAST_YEAR)
      sql += "PARTITION p_#{year} VALUES LESS THAN (#{year}) \
              (SUBPARTITION s_jan_#{year}, \
               SUBPARTITION s_feb_#{year}, \
               SUBPARTITION s_mar_#{year}, \
               SUBPARTITION s_apr_#{year}, \
               SUBPARTITION s_may_#{year}, \
               SUBPARTITION s_jun_#{year}, \
               SUBPARTITION s_jul_#{year}, \
               SUBPARTITION s_aug_#{year}, \
               SUBPARTITION s_sep_#{year}, \
               SUBPARTITION s_oct_#{year}, \
               SUBPARTITION s_nov_#{year}, \
               SUBPARTITION s_dec_#{year}),"
    end
    sql += "PARTITION p_all VALUES LESS THAN MAXVALUE \
            (SUBPARTITION s_jan_all, \
             SUBPARTITION s_feb_all, \
             SUBPARTITION s_mar_all, \
             SUBPARTITION s_apr_all, \
             SUBPARTITION s_may_all, \
             SUBPARTITION s_jun_all, \
             SUBPARTITION s_jul_all, \
             SUBPARTITION s_aug_all, \
             SUBPARTITION s_sep_all, \
             SUBPARTITION s_oct_all, \
             SUBPARTITION s_nov_all, \
             SUBPARTITION s_dec_all))"
    execute(sql);
  end


  def self.down
    drop_table :history_alerts
  end

end