mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Add support for UNLOGGED Postgresql tables
This commit adds support for the `ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables` setting, which turns `CREATE TABLE` SQL statements into `CREATE UNLOGGED TABLE` statements. This can improve PostgreSQL performance but at the cost of data durability, and thus it is highly recommended that you *DO NOT* enable this in a production environment.
This commit is contained in:
parent
82f2e9741f
commit
bfc4d8be0a
6 changed files with 118 additions and 1 deletions
|
@ -39,7 +39,7 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def visit_TableDefinition(o)
|
||||
create_sql = +"CREATE#{' TEMPORARY' if o.temporary} TABLE "
|
||||
create_sql = +"CREATE#{table_modifier_in_create(o)} TABLE "
|
||||
create_sql << "IF NOT EXISTS " if o.if_not_exists
|
||||
create_sql << "#{quote_table_name(o.name)} "
|
||||
|
||||
|
@ -121,6 +121,11 @@ module ActiveRecord
|
|||
sql
|
||||
end
|
||||
|
||||
# Returns any SQL string to go between CREATE and TABLE. May be nil.
|
||||
def table_modifier_in_create(o)
|
||||
" TEMPORARY" if o.temporary
|
||||
end
|
||||
|
||||
def foreign_key_in_create(from_table, to_table, options)
|
||||
options = foreign_key_options(from_table, to_table, options)
|
||||
accept ForeignKeyDefinition.new(from_table, to_table, options)
|
||||
|
|
|
@ -23,6 +23,17 @@ module ActiveRecord
|
|||
end
|
||||
super
|
||||
end
|
||||
|
||||
# Returns any SQL string to go between CREATE and TABLE. May be nil.
|
||||
def table_modifier_in_create(o)
|
||||
# A table cannot be both TEMPORARY and UNLOGGED, since all TEMPORARY
|
||||
# tables are already UNLOGGED.
|
||||
if o.temporary
|
||||
" TEMPORARY"
|
||||
elsif o.unlogged
|
||||
" UNLOGGED"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -175,6 +175,13 @@ module ActiveRecord
|
|||
class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
|
||||
include ColumnMethods
|
||||
|
||||
attr_reader :unlogged
|
||||
|
||||
def initialize(*)
|
||||
super
|
||||
@unlogged = ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables
|
||||
end
|
||||
|
||||
private
|
||||
def integer_like_primary_key_type(type, options)
|
||||
if type == :bigint || options[:limit] == 8
|
||||
|
|
|
@ -85,6 +85,18 @@ module ActiveRecord
|
|||
class PostgreSQLAdapter < AbstractAdapter
|
||||
ADAPTER_NAME = "PostgreSQL"
|
||||
|
||||
##
|
||||
# :singleton-method:
|
||||
# PostgreSQL allows the creation of "unlogged" tables, which do not record
|
||||
# data in the PostgreSQL Write-Ahead Log. This can make the tables faster,
|
||||
# bug significantly increases the risk of data loss if the database
|
||||
# crashes. As a result, this should not be used in production
|
||||
# environments. If you would like all created tables to be unlogged you
|
||||
# can add the following line to your test.rb file:
|
||||
#
|
||||
# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables = true
|
||||
class_attribute :create_unlogged_tables, default: false
|
||||
|
||||
NATIVE_DATABASE_TYPES = {
|
||||
primary_key: "bigserial primary key",
|
||||
string: { name: "character varying" },
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "cases/helper"
|
||||
require "support/schema_dumping_helper"
|
||||
|
||||
class UnloggedTablesTest < ActiveRecord::PostgreSQLTestCase
|
||||
include SchemaDumpingHelper
|
||||
|
||||
TABLE_NAME = "things"
|
||||
LOGGED_FIELD = "relpersistence"
|
||||
LOGGED_QUERY = "SELECT #{LOGGED_FIELD} FROM pg_class WHERE relname = '#{TABLE_NAME}'"
|
||||
LOGGED = "p"
|
||||
UNLOGGED = "u"
|
||||
TEMPORARY = "t"
|
||||
|
||||
class Thing < ActiveRecord::Base
|
||||
self.table_name = TABLE_NAME
|
||||
end
|
||||
|
||||
def setup
|
||||
@connection = ActiveRecord::Base.connection
|
||||
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables = false
|
||||
end
|
||||
|
||||
teardown do
|
||||
@connection.drop_table TABLE_NAME, if_exists: true
|
||||
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables = false
|
||||
end
|
||||
|
||||
def test_logged_by_default
|
||||
@connection.create_table(TABLE_NAME) do |t|
|
||||
end
|
||||
assert_equal @connection.execute(LOGGED_QUERY).first[LOGGED_FIELD], LOGGED
|
||||
end
|
||||
|
||||
def test_unlogged_in_test_environment_when_unlogged_setting_enabled
|
||||
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables = true
|
||||
|
||||
@connection.create_table(TABLE_NAME) do |t|
|
||||
end
|
||||
assert_equal @connection.execute(LOGGED_QUERY).first[LOGGED_FIELD], UNLOGGED
|
||||
end
|
||||
|
||||
def test_not_included_in_schema_dump
|
||||
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables = true
|
||||
|
||||
@connection.create_table(TABLE_NAME) do |t|
|
||||
end
|
||||
assert_no_match(/unlogged/i, dump_table_schema(TABLE_NAME))
|
||||
end
|
||||
|
||||
def test_not_changed_in_change_table
|
||||
@connection.create_table(TABLE_NAME) do |t|
|
||||
end
|
||||
|
||||
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables = true
|
||||
|
||||
@connection.change_table(TABLE_NAME) do |t|
|
||||
t.column :name, :string
|
||||
end
|
||||
assert_equal @connection.execute(LOGGED_QUERY).first[LOGGED_FIELD], LOGGED
|
||||
end
|
||||
|
||||
def test_gracefully_handles_temporary_tables
|
||||
@connection.create_table(TABLE_NAME, temporary: true) do |t|
|
||||
end
|
||||
|
||||
# Temporary tables are already unlogged, though this query results in a
|
||||
# different result ("t" vs. "u"). This test is really just checking that we
|
||||
# didn't try to run `CREATE TEMPORARY UNLOGGED TABLE`, which would result in
|
||||
# a PostgreSQL error.
|
||||
assert_equal @connection.execute(LOGGED_QUERY).first[LOGGED_FIELD], TEMPORARY
|
||||
end
|
||||
end
|
|
@ -379,6 +379,14 @@ The MySQL adapter adds one additional configuration option:
|
|||
|
||||
* `ActiveRecord::ConnectionAdapters::Mysql2Adapter.emulate_booleans` controls whether Active Record will consider all `tinyint(1)` columns as booleans. Defaults to `true`.
|
||||
|
||||
The PostgreSQL adapter adds one additional configuration option:
|
||||
|
||||
* `ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables`
|
||||
controls whether database tables created should be "unlogged," which can speed
|
||||
up performance but adds a risk of data loss if the database crashes. It is
|
||||
highly recommended that you do not enable this in a production environment.
|
||||
Defaults to `false` in all environments.
|
||||
|
||||
The SQLite3Adapter adapter adds one additional configuration option:
|
||||
|
||||
* `ActiveRecord::ConnectionAdapters::SQLite3Adapter.represent_boolean_as_integer`
|
||||
|
|
Loading…
Reference in a new issue