【问题标题】:Does PostgreSQL's VALIDATE CONSTRAINT check rows that were already checked?PostgreSQL 的 VALIDATE CONSTRAINT 是否检查已检查的行?
【发布时间】:2014-04-23 16:22:12
【问题描述】:

PostgreSQL's documentation 明确表示添加为NOT VALID 的约束仍将检查随后更新或插入的行。

我有一张“流失率”很高的桌子。也就是说,我知道在两周内,当前存在的大部分未选中的行都将被删除。并且将存在许多新行(将被检查)。

所以我的问题是:如果我延迟运行 VALIDATE CONSTRAINT 直到 2 周后,PostgreSQL 是否仍需要检查从现在到那时插入的所有行?或者它是否足够智能,可以知道哪些行已经被检查,从而减少了运行VALIDATE CONSTRAINT时排他锁所需的时间?

【问题讨论】:

    标签: postgresql foreign-keys


    【解决方案1】:

    我通过测试找到了答案。我用 Ruby 和 Active Record 编写了以下脚本:

    require "active_record"
    require "logger"
    
    ActiveRecord::Base.establish_connection(adapter: "postgresql", database: "test")
    ActiveRecord::Base.logger = Logger.new($stderr)
    
    ActiveRecord::Schema.define do
      create_table :befores, force: true do |t|
        t.integer :other_id
      end
    
      create_table :afters, force: true do |t|
        t.integer :other_id
      end
    
      create_table :others, force: true
    end
    
    conn = ActiveRecord::Base.connection
    
    conn.execute(
      "ALTER TABLE befores " \
      "ADD CONSTRAINT befores_others_fk " \
      "FOREIGN KEY (other_id) " \
      "REFERENCES others (id) " \
      "NOT VALID"
    )
    
    ActiveRecord::Base.logger = nil
    
    N = (ENV["N"] || 1_000_000).to_i
    
    print "Inserting #{N} rows..."
    N.times do |i|
      conn.execute("INSERT INTO others (id) VALUES (#{i})")
      conn.execute("INSERT INTO befores (id, other_id) VALUES (#{i}, #{i})")
      conn.execute("INSERT INTO afters (id, other_id) VALUES (#{i}, #{i})")
    end
    puts "done"
    
    ActiveRecord::Base.logger = Logger.new($stderr)
    
    conn.execute(
      "ALTER TABLE afters " \
      "ADD CONSTRAINT afters_others_fk " \
      "FOREIGN KEY (other_id) " \
      "REFERENCES others (id) " \
      "NOT VALID"
    )
    
    conn.execute "ALTER TABLE befores VALIDATE CONSTRAINT befores_others_fk"
    conn.execute "ALTER TABLE afters VALIDATE CONSTRAINT afters_others_fk"

    然后我用 100k 行运行它:

    $ N=100000 ruby test.rb 
    -- create_table(:befores, {:force=>true})
    D, [2014-04-23T23:00:41.925325 #6411] DEBUG -- :    (6.3ms)  DROP TABLE "befores"
    D, [2014-04-23T23:00:41.935557 #6411] DEBUG -- :    (9.6ms)  CREATE TABLE "befores" ("id" serial primary key, "other_id" integer) 
       -> 0.0322s
    -- create_table(:afters, {:force=>true})
    D, [2014-04-23T23:00:41.940595 #6411] DEBUG -- :    (3.3ms)  DROP TABLE "afters"
    D, [2014-04-23T23:00:41.948406 #6411] DEBUG -- :    (7.5ms)  CREATE TABLE "afters" ("id" serial primary key, "other_id" integer) 
       -> 0.0127s
    -- create_table(:others, {:force=>true})
    D, [2014-04-23T23:00:41.952883 #6411] DEBUG -- :    (3.0ms)  DROP TABLE "others"
    D, [2014-04-23T23:00:41.960750 #6411] DEBUG -- :    (7.5ms)  CREATE TABLE "others" ("id" serial primary key) 
       -> 0.0122s
    D, [2014-04-23T23:00:41.963809 #6411] DEBUG -- :    (2.7ms)  ALTER TABLE befores ADD CONSTRAINT befores_others_fk FOREIGN KEY (other_id) REFERENCES others (id) NOT VALID
    Inserting 100000 rows...done
    D, [2014-04-23T23:11:37.105878 #6411] DEBUG -- :    (3.3ms)  ALTER TABLE afters ADD CONSTRAINT afters_others_fk FOREIGN KEY (other_id) REFERENCES others (id) NOT VALID
    D, [2014-04-23T23:11:37.196819 #6411] DEBUG -- :    (90.7ms)  ALTER TABLE befores VALIDATE CONSTRAINT befores_others_fk
    D, [2014-04-23T23:11:37.287966 #6411] DEBUG -- :    (91.0ms)  ALTER TABLE afters VALIDATE CONSTRAINT afters_others_fk

    由于最后两个语句之间没有真正的区别,我的结论是在运行VALIDATE CONSTRAINT 时确实会重新检查所有行。用于测试的postgres版本是9.2.6。

    【讨论】:

      猜你喜欢
      • 2021-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-09
      • 2015-11-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多