postgreSQL分区表在rails的应用

postgerSQL 是通过表继承来实现分区表的。表分区就是把逻辑上的一个大表分割成物理上的几个小块,分区可以提供若干好处。

  • 删除历史数据更快,如果是按时间分区的,在删除历史数据时,直接删除历史分区就可以了,如果没有分区,通过 DELETE 删除数据时会比较慢,还容易导致 VACUUM 超载;

  • 某些类型的查询性能可以得到极大的提升,特别是表中访问率较高的行位于一个单独分区或少数几个分区的情况下。如果在按时间分区的表中,大多数查询发生在时间最近的一个分区或几个分区中,而较早时间分区比较少查询,那么,在建分区表后各个分区表会有各自的索引,使用率较高的分区表的索引就可能完全缓存在内存中,这样效率就会高很多;

  • 当查询或更新一个分区的大部分记录时,连续扫描那个分区而不是使用索引离散的访问整个表,可以获得巨大的性能提升;

  • 很少用到的历史数据可以使用表空间的技术移动到便宜一些的慢速存储介质上,因为使用分区表可以将不同的分区安置在不同的物理介质上。

什么时候该使用分区表?

一般取决于具体应用,不过也有个基本的简单原则,即表的大小超过了数据库服务器的物理内存大小则应该使用

使用分区表时,一般都让父表为空,数据都存在子表中

建分区表的步骤

  1. 创建父表,所有的分区都从它继承。这个表中没有数据,不要在这个表上定义任何检查约束,除非你希望约束所有的分区。同样,在其上定义任何索引或唯一约束也没有任何意义。

  2. 创建几个子表,每个都是从主表上继承的。通常,这些表不会增加任何字段。我们把子表称作分区,实际上他们就是普通的 postgreSQL 表

  3. 给分区表增加约束,定义每隔分区允许的键值。

  4. 对于每个分区,在关键字字段上创建一个索引,也可以创建其它你想创建的索引。严格来说,关键字索引并非是必须的,但是大多情况下他是很有帮助的,如果你希望关键字是唯一的,那么应该总是给每个分区创建一个唯一约束或主键约束。

  5. 定义一个规则或者触发器,把对主表的数据插入重定向到合适的分区表。

  6. 确保 postgresql.conf 里的配置参数 constaint_exclusion(约束排除) 是打开的。打开后,如果查询中的 WHERE 子句的过滤条件与分区的约束条件匹配,那么这个查询会智能的只查询这个分区,而不会查询其他分区。 在 9.2.4 以后的版本中, 参数 constaint_exclusion 默认就是 partition。 如果设置成 off 则会扫描每张分区子表。

在 rails 中的应用

rails 没有提供专有的方法来设置分区表,需要我们编写 SQL 语句手动设置。分区表与触发器的创建自然是写在迁移文件中

下面是 按商标的长度不同,把商标数据存入不同的表中 的例子

创建父表

class CreateTrademarkWords < ActiveRecord::Migration[5.2]
  def change
    create_table :trademark_words do |t|
      t.string :name
      t.integer :length
      t.string :origin

      t.timestamps
    end
  end
end

创建子表及触发器

class CreatePartitionTableOfTrademarkWords < ActiveRecord::Migration[5.2]
  def up
    # 注意如何在 rails 中编写 SQL
    execute <<~SQL
    CREATE TABLE trademark_words_1 (CHECK (length = 1)) INHERITS (trademark_words);
    CREATE INDEX length_1_index_name ON trademark_words_1 (name);
    CREATE INDEX length_1_index_origin ON trademark_words_1 (origin);

    CREATE TABLE trademark_words_2 (CHECK (length = 2))   INHERITS (trademark_words);
    CREATE INDEX length_2_index_name ON trademark_words_2 (name);
    CREATE INDEX length_2_index_origin ON trademark_words_2 (origin);

    CREATE TABLE trademark_words_3 (CHECK (length = 3))   INHERITS (trademark_words);
    CREATE INDEX length_3_index_name ON trademark_words_3(name);
    CREATE INDEX length_3_index_origin ON trademark_words_3 (origin);

    CREATE TABLE trademark_words_4 (CHECK (length = 4))   INHERITS (trademark_words);
    CREATE INDEX length_4_index_name ON trademark_words_4(name);
    CREATE INDEX length_4_index_origin ON trademark_words_4 (origin);

    CREATE TABLE trademark_words_5 (CHECK (length = 5))   INHERITS (trademark_words);
    CREATE INDEX length_5_index_name ON trademark_words_5(name);
    CREATE INDEX length_5_index_origin ON trademark_words_5 (origin);

    # 触发器
    CREATE OR REPLACE FUNCTION trademark_words_insert_trigger()
    RETURNS TRIGGER AS $$
    BEGIN
        IF ( NEW.length = 1 ) THEN
             INSERT INTO trademark_words_1 VALUES (NEW.*);
        ELSIF ( NEW.length = 2) THEN
             INSERT INTO trademark_words_2 VALUES (NEW.*);
        ELSIF ( NEW.length = 3) THEN
             INSERT INTO trademark_words_3 VALUES (NEW.*);
        ELSIF ( NEW.length = 4) THEN
             INSERT INTO trademark_words_4 VALUES (NEW.*);
        ELSIF ( NEW.length = 5) THEN
             INSERT INTO trademark_words_5 VALUES (NEW.*);
        ELSE
        RAISE EXCEPTION 'Length out of range. Fix the trademark_words_insert_trigger() function!';
        END IF;
        RETURN NULL;
    END;
    $$
    LANGUAGE plpgsql;
    CREATE TRIGGER insert_trademark_words
        BEFORE INSERT ON trademark_words
        FOR EACH ROW EXECUTE PROCEDURE trademark_words_insert_trigger();
    SQL

  end

  # 回滚操作
  def down
    execute <<~SQL
            DROP TABLE trademark_words_1;
            DROP TABLE trademark_words_2;
            DROP TABLE trademark_words_3;
            DROP TABLE trademark_words_4;
            DROP TABLE trademark_words_5;
            DROP TRIGGER insert_trademark_words ON trademark_words;
          SQL

  end
end

`

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,752评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,100评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,244评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,099评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,210评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,307评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,346评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,133评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,546评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,849评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,019评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,702评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,331评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,030评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,260评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,871评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,898评论 2 351

推荐阅读更多精彩内容

  • ORA-00001: 违反唯一约束条件 (.) 错误说明:当在唯一索引所对应的列上键入重复值时,会触发此异常。 O...
    我想起个好名字阅读 5,267评论 0 9
  • ORA-13000: 维数超出范围 ORA-13001: 维数不匹配错误 ORA-13002: 指定的级别超出范围...
    thinkact阅读 19,145评论 1 5
  • 今天看到一位朋友写的mysql笔记总结,觉得写的很详细很用心,这里转载一下,供大家参考下,也希望大家能关注他原文地...
    信仰与初衷阅读 4,727评论 0 30
  • 4.1 索引组织表 在lnnoDB存储引擎中, 表都是根据主键顺序组织存放的, 这种存储方式的表称为索引组织表(...
    好好学习Sun阅读 612评论 0 0
  • 老李头赶集回家的路上,正骑着“嘉陵”慢慢跑着,突然前边停下来一个人,向他打招呼,伙计,恁好时气,前边树底下有个好东...
    南良大维阅读 328评论 0 3