<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Andrew Atkinson</title>
    <description>The latest articles on DEV Community by Andrew Atkinson (@andatki).</description>
    <link>https://dev.to/andatki</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F125068%2Fde75092b-07bc-45d4-b951-ede95b69664c.jpg</url>
      <title>DEV Community: Andrew Atkinson</title>
      <link>https://dev.to/andatki</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/andatki"/>
    <language>en</language>
    <item>
      <title>What's Coming in Ruby on Rails 7.2: Database Features in Active Record</title>
      <dc:creator>Andrew Atkinson</dc:creator>
      <pubDate>Wed, 07 Aug 2024 14:00:00 +0000</pubDate>
      <link>https://dev.to/appsignal/whats-coming-in-ruby-on-rails-72-database-features-in-active-record-5kf</link>
      <guid>https://dev.to/appsignal/whats-coming-in-ruby-on-rails-72-database-features-in-active-record-5kf</guid>
      <description>&lt;p&gt;Ruby on Rails is currently in major version 7.1 and rolling towards Rails 8, the next comprehensive new release.&lt;/p&gt;

&lt;p&gt;Before Rails 8, though, there’s a significant version that will help bridge the gap: Ruby on Rails 7.2.&lt;/p&gt;

&lt;p&gt;In this post, we’ll dive into several noteworthy changes in Ruby on Rails 7.2, focusing on the support for database changes in Active Record.&lt;/p&gt;

&lt;p&gt;You'll come away with hands-on opportunities to work with these features.&lt;/p&gt;

&lt;p&gt;Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Active Record Database-Related Features in Ruby on Rails 7.2
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://guides.rubyonrails.org/active_record_basics.html" rel="noopener noreferrer"&gt;Active Record&lt;/a&gt; object-relational mapper (ORM) supports three open-source relational database management systems: MySQL, PostgreSQL, and SQLite. Active Record is most commonly thought of for its ORM facilities, mapping between database operations and database types to Ruby methods and types. However, besides the ORM, Active Record has mechanisms to evolve your database schema definition, capturing incremental changes and a representation of the entire schema in Ruby files or SQL files.&lt;/p&gt;

&lt;p&gt;Active Record can connect a single Rails app to multiple databases, and those databases can have distinct roles. The databases might have writer or reader roles or even be “shards” that leverage the &lt;a href="https://rubyonrails.org/2020/12/9/Rails-6-1-0-release" rel="noopener noreferrer"&gt;Horizontal Sharding feature&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Recently, Beta releases of 7.2 have shipped, allowing developers to preview what’s changed.&lt;/p&gt;

&lt;p&gt;As we roll towards Rails 8, we must first pass through 7.2. Let’s examine what's in this release.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s New with Composite Primary Keys (CPKs)
&lt;/h2&gt;

&lt;p&gt;Rails 7.1 brought us the first release of composite primary keys (CPKs). What are CPKs? First, let’s talk about unique identifiers in databases more generally. Uniquely identifying rows can take the shape of “natural keys” or “surrogate keys”. Since most databases use surrogate keys, let’s focus on those. Surrogate keys are when “id” integer values are used to uniquely identify a row. This is a surrogate in that it’s not directly related to the data row.&lt;/p&gt;

&lt;p&gt;In Rails, the surrogate primary key is usually a column called “id” with an integer type, populated by the database. In PostgreSQL, a sequence object usually provides the value.&lt;/p&gt;

&lt;p&gt;What does this have to do with indexes? When we define our &lt;code&gt;id&lt;/code&gt; column as the primary key column, this creates a primary key constraint on the table, and constraints have a supporting index. Primary key constraints enforce unique values, and the index helps the lookups performed to enforce that rule to run quickly.&lt;/p&gt;

&lt;p&gt;CPKs, or multi-column primary keys, are primary keys where multiple columns uniquely identify a table row. This is a generic mechanism, so it’s up to you as to how you describe your CPK. You may choose to incorporate a surrogate value like the &lt;code&gt;id&lt;/code&gt; integer, and combine that with a unique identifier for one of your customers, for example, a &lt;code&gt;customer_id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You may choose a CPK as a natural key composed of two foreign key columns that point to other tables. This structure is most common with &lt;em&gt;join tables&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;With that context in mind, let's arrive at what’s changing in Rails 7.2.&lt;/p&gt;

&lt;p&gt;Currently, for the CPK feature, we use the &lt;code&gt;query_constraints&lt;/code&gt; keyword on models that relate to other models, and supply a list of foreign key columns that refer to the foreign table primary key columns.&lt;/p&gt;

&lt;p&gt;In Rails 7.2, this option changes from &lt;code&gt;query_constraints&lt;/code&gt; to &lt;code&gt;foreign_keys&lt;/code&gt;. Besides the parameter name change, some interesting discussions are underway about plans to &lt;a href="https://github.com/rails/rails/pull/51571" rel="noopener noreferrer"&gt;repurpose the original &lt;code&gt;query_constraints&lt;/code&gt; name&lt;/a&gt; by freeing it up.&lt;/p&gt;

&lt;p&gt;If you’d like to play around with single-column surrogate keys, and compare them with composite or multi-column primary keys as a type of natural key, take a look at &lt;a href="https://github.com/andyatkinson/bookshop" rel="noopener noreferrer"&gt;this Bookshop repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here, we’ve got the models listed in the Rails API documentation for CPKs implemented as a single file Rails app. You can modify the code and database schema design and try out different alternatives.&lt;/p&gt;

&lt;p&gt;To try out Rails 7.2 changes, edit the Gemfile portion within the &lt;code&gt;bookshop.rb&lt;/code&gt; Ruby file. Use a 7.2 beta version by putting this change into the file, then running &lt;code&gt;bundle install&lt;/code&gt; from your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'rails'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'~&amp;gt; 7.2.0.beta1'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Development Containers and Databases in Rails 7.2
&lt;/h2&gt;

&lt;p&gt;Ruby on Rails has always been a productivity-centric framework. One challenge that impacts the developer experience and productivity is creating and maintaining a development environment.&lt;/p&gt;

&lt;p&gt;Dev containers intend to fix that. They're used to create reproducible development environments that anyone on your team can run.&lt;/p&gt;

&lt;p&gt;Besides reproducibility, another benefit is the isolation of environment dependencies. Some operating system dependencies you use can be particularly challenging to install, or multiple versions might coexist. By isolating dependencies into a container, you can avoid those pitfalls.&lt;/p&gt;

&lt;p&gt;Dev containers use Docker, but add a “devcontainer.json” file to the mix. This can describe the text editor configuration and be shared on a team that uses the same editor and configuration.&lt;/p&gt;

&lt;p&gt;Let’s generate a new app with a dev container within the bookshop repository. Make sure that Rails 7.2 is the version used by the rails executable, installing the gem if needed.&lt;/p&gt;

&lt;p&gt;We'll add &lt;code&gt;--database=postgresql&lt;/code&gt; which will configure a Postgres instance in Docker, and install the &lt;code&gt;pg&lt;/code&gt; gem for the generated Rails app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gem &lt;span class="nb"&gt;install &lt;/span&gt;rails &lt;span class="nt"&gt;-v&lt;/span&gt; 7.2.0.beta1 &lt;span class="c"&gt;# if needed&lt;/span&gt;

rails new myapp &lt;span class="nt"&gt;--database&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgresql &lt;span class="nt"&gt;--devcontainer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open "myapp" in VS Code from the interface or by running &lt;code&gt;code myapp&lt;/code&gt; when the &lt;code&gt;code&lt;/code&gt; executable is available.&lt;/p&gt;

&lt;p&gt;Once in VS Code, if not auto-detected, run "Command-shift-P" and choose “Dev Container: Rebuild in Container”. You'll see “Starting Dev Container”, which starts up Docker as needed.&lt;/p&gt;

&lt;p&gt;Click “Show Log” to expand the terminal area, showing log progress. Here, you can tell whether containers are being downloaded and which stage they’re in.&lt;/p&gt;

&lt;p&gt;The containers can be viewed and administered using Docker Desktop.&lt;/p&gt;

&lt;p&gt;The Rails app, Postgres, and all its gem dependencies should now be running inside the container.&lt;/p&gt;

&lt;p&gt;Open a terminal in VS Code and run &lt;code&gt;bin/rails server&lt;/code&gt;. Navigate to &lt;code&gt;localhost:3000&lt;/code&gt; in your browser. Since there’s a local port mapping from 3000 into the container, you should see the generated Rails 7.2 app welcome page!&lt;/p&gt;

&lt;p&gt;If you run into issues, visit the &lt;a href="https://github.com/andyatkinson/bookshop" rel="noopener noreferrer"&gt;bookshop repo&lt;/a&gt; for more information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Database Transaction Enhancements, Solid Queue, and Active Job
&lt;/h2&gt;

&lt;p&gt;Transactions are one of the fundamental concepts of relational databases. Databases are designed to support high concurrent access to shared resources, like table row data. For example, multiple clients might try to read and write to the same table row at once. The database consistently processes operations by using transactions with an isolated view of the data.&lt;/p&gt;

&lt;p&gt;One of the problems in Rails apps comes when working with relational database transactions and then with another data store like Redis (via background processing with Sidekiq or other Active Job backends).&lt;/p&gt;

&lt;p&gt;The issue is one of timing: ensuring data is committed to the relational database before any background work starts.&lt;/p&gt;

&lt;p&gt;With Solid Queue — a database-backed queue management system — coming in Rails 8, ensuring transactionally consistent data and operational order is even more important. Transactional consistency errors will become more visible when there's a first-party database-backed queue system.&lt;/p&gt;

&lt;p&gt;To prepare for that, what's changed in Rails 7.2? Active Job will now defer enqueuing background jobs until &lt;em&gt;after&lt;/em&gt; a database transaction has been committed. This small change ensures no background job processing starts until the database transaction is committed.&lt;/p&gt;

&lt;p&gt;Another change in 7.2 is that callbacks will be registered on database transactions.&lt;/p&gt;

&lt;p&gt;For example, &lt;a href="https://edgeguides.rubyonrails.org/7_2_release_notes.html#per-transaction-commit-and-rollback-callbacks" rel="noopener noreferrer"&gt;&lt;code&gt;after_commit&lt;/code&gt;&lt;/a&gt; can be added within a transaction block to ensure that it runs after the transaction is committed.&lt;/p&gt;

&lt;p&gt;Here's the example used in the release notes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;published: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;after_commit&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# Do work after commit, like send a notification email&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach ensures the code in the &lt;code&gt;after_commit&lt;/code&gt; block runs after the article is updated.&lt;/p&gt;

&lt;h2&gt;
  
  
  New Active Support Instrumentation for Transactions
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/rails/rails/releases/tag/v7.2.0.beta3" rel="noopener noreferrer"&gt;Beta 3 version of Rails 7.2&lt;/a&gt; was recently released, and it included new Active Support Instrumentation events we can configure for our applications.&lt;/p&gt;

&lt;p&gt;One of these new events is called &lt;code&gt;start_transaction.active_record&lt;/code&gt;, and it is triggered when database transactions or savepoints within transactions are started.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Check out the blog post &lt;a href="https://andyatkinson.com/blog/2024/07/22/postgresql-savepoints" rel="noopener noreferrer"&gt;You make a good point! — PostgreSQL Savepoints&lt;/a&gt; for more information on savepoints.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When database transactions finish, the event &lt;code&gt;transaction.active_record&lt;/code&gt; event is emitted.&lt;/p&gt;

&lt;p&gt;What can we do with these events? By creating an &lt;a href="https://api.rubyonrails.org/classes/ActiveSupport/Subscriber.html" rel="noopener noreferrer"&gt;Active Support Subscriber&lt;/a&gt; that inspects these events and their payloads, we can gain a better understanding of database transaction and savepoint activity within Active Record.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/rails/rails/commit/6a05a391999dd8201706516b440ef8b9b8527161" rel="noopener noreferrer"&gt;Check out the commit code changes and documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In this post, we looked at a few database-related features coming in Ruby on Rails 7.2. We covered the basics of CPKs and an important option name that's changing in 7.2. We also examined how we'll be able to run all of our application dependencies (including our databases) in a dev container.&lt;/p&gt;

&lt;p&gt;Finally, we covered how database transactions and database-backed background job systems will tackle the challenge of write operations occurring in the expected order.&lt;/p&gt;

&lt;p&gt;Besides those items, there's plenty more to read and learn about Rails 7.2. For example, Ruby 3.1 will become the new default minimum version, there will be support for jemalloc, RuboCop rules, a GitHub CI workflow, and support for progressive web apps (PWAs). To learn more, check out the &lt;a href="https://edgeguides.rubyonrails.org/7_2_release_notes.html" rel="noopener noreferrer"&gt;Rails 7.2 release notes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;P.S. If you'd like to read Ruby Magic posts as soon as they get off the press, &lt;a href="https://blog.appsignal.com/ruby-magic" rel="noopener noreferrer"&gt;subscribe to our Ruby Magic newsletter and never miss a single post&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
    </item>
    <item>
      <title>Upcoming Book Launch: High Performance PostgreSQL for Rails</title>
      <dc:creator>Andrew Atkinson</dc:creator>
      <pubDate>Sat, 19 Aug 2023 13:23:14 +0000</pubDate>
      <link>https://dev.to/andatki/upcoming-book-launch-high-performance-postgresql-for-rails-c9k</link>
      <guid>https://dev.to/andatki/upcoming-book-launch-high-performance-postgresql-for-rails-c9k</guid>
      <description>&lt;p&gt;Hello! 👋 I’m the author of “High Performance PostgreSQL for Rails” being published by Pragmatic Programmers. The Beta launch is coming up in less than 2 weeks!&lt;/p&gt;

&lt;p&gt;Subscribe to 👉&lt;a href="http://pgrailsbook.com" rel="noopener noreferrer"&gt;http://pgrailsbook.com&lt;/a&gt; to be among the first to know when it’s live. You’ll also receive exclusive content and a discount code once it’s live.&lt;/p&gt;

&lt;p&gt;Subscribers also get access to summaries of 40+ Ruby gems and PostgreSQL extensions mentioned in the book.&lt;/p&gt;

&lt;p&gt;Thanks for taking a look! 😊&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>rails</category>
      <category>ruby</category>
      <category>sql</category>
    </item>
    <item>
      <title>Ruby For All Podcast: My Guest Experience 🎙️</title>
      <dc:creator>Andrew Atkinson</dc:creator>
      <pubDate>Thu, 02 Feb 2023 15:45:51 +0000</pubDate>
      <link>https://dev.to/andatki/ruby-for-all-podcast-my-guest-experience-2do1</link>
      <guid>https://dev.to/andatki/ruby-for-all-podcast-my-guest-experience-2do1</guid>
      <description>&lt;p&gt;This post has moved!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://andyatkinson.com/blog/2023/01/19/ruby-for-all-podcast-guest-postgresql" rel="noopener noreferrer"&gt;https://andyatkinson.com/blog/2023/01/19/ruby-for-all-podcast-guest-postgresql&lt;/a&gt;&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>ruby</category>
      <category>podcast</category>
    </item>
    <item>
      <title>How Long Does It Take To Create An Index?</title>
      <dc:creator>Andrew Atkinson</dc:creator>
      <pubDate>Mon, 16 Jan 2023 00:20:06 +0000</pubDate>
      <link>https://dev.to/andatki/how-long-does-it-take-to-create-an-index-60o</link>
      <guid>https://dev.to/andatki/how-long-does-it-take-to-create-an-index-60o</guid>
      <description>&lt;p&gt;A &lt;a href="https://twitter.com/petervanderdoes/status/1614631740424818689" rel="noopener noreferrer"&gt;recent tweet&lt;/a&gt; asked the following question.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does anybody know how long it should take to create an index of two integer columns with approximately 110 Million records in the DB? #postgres #postgresql #NotAnDBA&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's put together an experiment. Create a table with 2 columns populated with 110,000,000 million rows. Each column has a random integer value.&lt;/p&gt;

&lt;p&gt;Use the command line psql client that’s included with PostgreSQL to create the index. &lt;/p&gt;

&lt;p&gt;To see how long the &lt;code&gt;CREATE INDEX&lt;/code&gt; statement will take toggle &lt;code&gt;\timing&lt;/code&gt; from psql.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Populate 110,000,000 million records&lt;/span&gt;
&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RANDOM&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RANDOM&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)::&lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;GENERATE_SERIES&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;110000000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Confirm 110,000,000 records&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;count&lt;/span&gt;
&lt;span class="c1"&gt;-----------&lt;/span&gt;
 &lt;span class="mi"&gt;110000000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable timing to collect the duration of running the &lt;code&gt;CREATE INDEX&lt;/code&gt; statement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- turn timing on&lt;/span&gt;
&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="n"&gt;timing&lt;/span&gt;
&lt;span class="n"&gt;Timing&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;

&lt;span class="c1"&gt;-- Create index "t_a_idx" on table "t" on the "a" column&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;t_a_idx&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nb"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;52348&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;022&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;00&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;52&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;348&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Answer
&lt;/h2&gt;

&lt;p&gt;In this test, it took about 52 seconds to create the index.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test Environment Details
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Tested on a M1 MacBook Air with 16GB RAM.&lt;/li&gt;
&lt;li&gt;The table has no sequences, constraints, or other indexes&lt;/li&gt;
&lt;li&gt;Vacuum was running but was cancelled when the &lt;code&gt;CREATE INDEX&lt;/code&gt; started according to the &lt;code&gt;postgresql.log&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;No other queries were running on the table.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This post is intended to be a demonstration of how to conduct this sort of experiment on your own and some of the factors that contribute to the time needed for index creation. &lt;/p&gt;

&lt;p&gt;The best way to answer questions like this is to create a test on your own server instance or using a separate disconnected instance made from a snapshot. &lt;/p&gt;

&lt;p&gt;In a production system with live queries, use the &lt;code&gt;CONCURRENTLY&lt;/code&gt; keyword when creating indexes. While this lengthens the time to create the index, it avoids &lt;a href="https://www.postgresql.org/docs/current/sql-createindex.html" rel="noopener noreferrer"&gt;blocking concurrent write operations&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Collect timing info
&lt;/h2&gt;

&lt;p&gt;This experiment could be considered a best case scenario for my machine. The data was loaded into a minimal set of pages, with inserts and no updates or deletes. There were no other queries or background processes running.&lt;/p&gt;

&lt;p&gt;A best case scenario gives us a starting point, but the best way to answer this question will be to try this out on your system. Good luck!&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>sql</category>
    </item>
    <item>
      <title>Upgrading to PostgreSQL 15 on Mac OS</title>
      <dc:creator>Andrew Atkinson</dc:creator>
      <pubDate>Wed, 11 Jan 2023 16:24:27 +0000</pubDate>
      <link>https://dev.to/andatki/upgrading-to-postgresql-15-on-mac-os-ibg</link>
      <guid>https://dev.to/andatki/upgrading-to-postgresql-15-on-mac-os-ibg</guid>
      <description>&lt;p&gt;This post has moved!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://andyatkinson.com/blog/2022/12/12/upgrading-postgresql-15-mac-os" rel="noopener noreferrer"&gt;https://andyatkinson.com/blog/2022/12/12/upgrading-postgresql-15-mac-os&lt;/a&gt;&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>upgrades</category>
      <category>devops</category>
    </item>
    <item>
      <title>Dump and Restore PostgreSQL Tables</title>
      <dc:creator>Andrew Atkinson</dc:creator>
      <pubDate>Fri, 16 Aug 2019 17:27:48 +0000</pubDate>
      <link>https://dev.to/andatki/dump-and-load-a-postgresql-table-p0o</link>
      <guid>https://dev.to/andatki/dump-and-load-a-postgresql-table-p0o</guid>
      <description>&lt;p&gt;Sometimes it's helpful to dump an exact copy of a database table so it can be loaded elsewhere. How can you do that? &lt;/p&gt;

&lt;p&gt;In this example, we will dump and restore a table and assume there is no sensitive content in the table being dumped.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;pg_dump&lt;/code&gt; can be used to dump table content to a file. By using compression the file size can be kept small even for large tables. &lt;/p&gt;

&lt;p&gt;Specify the output format with &lt;code&gt;--format&lt;/code&gt; (or &lt;code&gt;-F&lt;/code&gt;). The &lt;code&gt;c&lt;/code&gt; format is the default. Refer to &lt;a href="https://www.postgresql.org/docs/current/app-pgdump.html" rel="noopener noreferrer"&gt;&lt;code&gt;pg_dump&lt;/code&gt; Docs&lt;/a&gt; for each of the options and values.&lt;/p&gt;

&lt;p&gt;Without compression, the file would be 144MB file from a &lt;code&gt;users&lt;/code&gt; table with &lt;code&gt;1042368&lt;/code&gt; rows. With compression it is 19MB. Compression is continually being improved so this might be even better in newer versions of PostgreSQL or by using external compression programs. &lt;/p&gt;

&lt;p&gt;In the example below, the database name is &lt;code&gt;rideshare_development&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;pg_dump&lt;/code&gt; as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pg_dump &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;c &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--host&lt;/span&gt; localhost &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--table&lt;/span&gt; &lt;span class="nb"&gt;users&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    rideshare_development &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; users_table.dump
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;du&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt; users_table.dump
19M    users_table.dump
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the &lt;code&gt;.dump&lt;/code&gt; file, the table and all the data rows can be populated into a database where neither exists.&lt;/p&gt;

&lt;p&gt;Create a database to create the table and populate it. Call the database &lt;code&gt;temp_load&lt;/code&gt;. The command below uses the createdb command line program included with PostgreSQL. The next command loads the content of the dump file using pg_restore.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;createdb temp_load&lt;span class="p"&gt;;&lt;/span&gt;

pg_restore &lt;span class="nt"&gt;--dbname&lt;/span&gt; temp_load users_table.dump
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Confirm all the rows are there&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;count&lt;/span&gt;
&lt;span class="c1"&gt;---------&lt;/span&gt;
 &lt;span class="mi"&gt;1042368&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! Note that this is only one of the ways to dump and restore table rows. Explore the PostgreSQL documentation for more options. &lt;/p&gt;

</description>
      <category>database</category>
      <category>postgres</category>
    </item>
  </channel>
</rss>
