This project is archived and is in readonly mode.
column_definitions method being called before and after every single SQL statement on PostgreSQL
Reported by Richard Adams | August 17th, 2010 @ 12:28 PM | in 3.0.2
On both Rails 3.0.0.rc and edge, every single request made by an active record object to a PostgreSQL database im getting this very time consuming sql statement
SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull
FROM pg_attribute a LEFT JOIN pg_attrdef d
ON a.attrelid = d.adrelid AND a.attnum = d.adnum
WHERE a.attrelid = '"table_name"'::regclass
AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum
which i believe is something to do with the column_definitions method in the Postgresql Adapter, also i think its has something to do with #4991
below is part of the development logs
SQL (1.3ms) SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull
FROM pg_attribute a LEFT JOIN pg_attrdef d
ON a.attrelid = d.adrelid AND a.attnum = d.adnum
WHERE a.attrelid = '"users"'::regclass
AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum
User Load (0.5ms) SELECT "users".* FROM "users" WHERE ("users"."id" = 1) LIMIT 1
SQL (1.0ms) SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull
FROM pg_attribute a LEFT JOIN pg_attrdef d
ON a.attrelid = d.adrelid AND a.attnum = d.adnum
WHERE a.attrelid = '"users"'::regclass
AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum
SQL (1.1ms) SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull
FROM pg_attribute a LEFT JOIN pg_attrdef d
ON a.attrelid = d.adrelid AND a.attnum = d.adnum
WHERE a.attrelid = '"sections"'::regclass
AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum
Section Load (0.5ms) SELECT "sections"."id", "sections"."name", "sections"."title", "sections"."description" FROM "sections" WHERE ("sections"."id" = 1) LIMIT 1
SQL (1.1ms) SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull
FROM pg_attribute a LEFT JOIN pg_attrdef d
ON a.attrelid = d.adrelid AND a.attnum = d.adnum
WHERE a.attrelid = '"sections"'::regclass
AND a.attnum > 0 AND NOT a.attisdropped
ORDER BY a.attnum
Sorry i cant be anymore help to you guys
Comments and changes to this ticket
-
Brandon Keene August 26th, 2010 @ 03:27 PM
I am seeing this too on RC. It's a real performance problem.
-
Tor Erik August 27th, 2010 @ 09:38 AM
I can cofirm that I see the same problem with rc2 in production mode using Ruby 1.9.2.p0 and pg 0.9.0.
-
Tor Erik August 27th, 2010 @ 10:16 AM
Sorry, that was supposed to be in development mode. When cache_classes = true, they only appear once.
-
Tor Erik August 27th, 2010 @ 10:51 AM
This works as expected
User.first User Load (0.5ms) SELECT "users".* FROM "users" INNER JOIN "countries" ON "countries"."id" = "users"."country_id" LIMIT 1
This however, does not:
User.joins(:country).first SQL (0.6ms) SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull FROM pg_attribute a LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum WHERE a.attrelid = '"countries"'::regclass AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum SQL (0.7ms) SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull FROM pg_attribute a LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum WHERE a.attrelid = '"users"'::regclass AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum SQL (0.7ms) SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull FROM pg_attribute a LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum WHERE a.attrelid = '"countries"'::regclass AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum User Load (0.5ms) SELECT "users".* FROM "users" INNER JOIN "countries" ON "countries"."id" = "users"."country_id" LIMIT 1
The above repeats every time I run the command on the console, not just the first time.
-
Szymon Nowak August 27th, 2010 @ 01:28 PM
Guys, have you tried running the same queries in production environment? It seems that Rails is properly caching column info there and these queries don't show up anymore every time.
-
MikZ September 2nd, 2010 @ 02:58 AM
Sure we tried.
SQL (0.9ms) SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull FROM pg_attribute a LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum WHERE a.attrelid = '"orders"'::regclass AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum SQL (2.5ms) SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull FROM pg_attribute a LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum WHERE a.attrelid = '"orders"'::regclass AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum Order Load (1.1ms) SELECT "orders".* FROM "orders" WHERE ("orders"."closed" = 'f') AND ("orders"."cancelled" = 'f') Rendered reservations/_order.html.erb (28.3ms) Court Load (0.7ms) SELECT "courts".* FROM "courts" WHERE ("courts".sport_id = 1) ORDER BY courts.number ASC SQL (0.8ms) SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull FROM pg_attribute a LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum WHERE a.attrelid = '"items"'::regclass AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum Item Load (0.5ms) SELECT "items".* FROM "items" WHERE ("items"."favourite" = 't') SQL (1.4ms) SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull FROM pg_attribute a LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum WHERE a.attrelid = '"items"'::regclass AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum Item Load (1.2ms) SELECT "items".* FROM "items" WHERE ("items"."favourite" = 'f') ORDER BY id ASC
and so on....
This is really performance issue. -
Rodrigo Kochenburger September 9th, 2010 @ 06:25 PM
Yes, it seems to happen only in development but still very annoying. Some pages involving a greater number of queries takes almost 5 seconds to render!!
-
Mateusz Drożdżyński September 21st, 2010 @ 10:37 AM
We diagnosed it only happens when Arel fetches columns independently of ActiveRecord. In AR table columns are memoised in @@@ActiveRecord::Base#columns@@@, so only the first invocation will trigger a database query. Arel also supports memoisation in its @@@Arel::Table#columns@@@ method, but it doesn't seem to work in some cases.
Consider this example:
> User.first > User.last
The first query will fetch U@@@ser#columns@@@ and subsequent calls will not run it again, as expected. Let's try a different model:
> Score.first > Score.last
Same story, Score#columns is memoised and no further calls to the database are made to fetch attributes.
The problem arises when Arel tries to reference other columns internally. Consider this query:
> User.joins(:scores)
The join is handled by Arel, not by ActiveRecord (@@@Score#columns@@@ is never called). Arel creates a new Table object to check the attributes of the scores table (by calling @@@table = Arel::Table.new(:scores)@@@) and in that call, all calls to table.columns are memoised. You'd expect that when you run @@@User.joins(:scores)@@@ again everything is returned from memory without any unnecessary database calls. This isn't the case though. Arel initialises the table again by calling @@@Arel::Table#new@@@ and previously cached columns are lost.
-
Mateusz Drożdżyński September 21st, 2010 @ 10:40 AM
We diagnosed it only happens when Arel fetches columns independently of ActiveRecord. In AR table columns are memoised in
ActiveRecord::Base#columns
, so only the first invocation will trigger a database query. Arel also supports memoisation in itsArel::Table#columns
method, but it doesn't seem to work in some cases.Consider this example:
> User.first > User.last
The first query will fetch
User#columns
and subsequent calls will not run it again, as expected. Let's try a different model:> Score.first > Score.last
Same story,
Score#columns
is memoised and no further calls to the database are made to fetch attributes.The problem arises when Arel tries to reference other columns internally. Consider this query:
> User.joins(:scores)
The join is handled by Arel, not by ActiveRecord (
Score#columns
is never called). Arel creates a new Table object to check the attributes of the scores table (by callingtable = Arel::Table.new(:scores)
) and in that call, all calls to table.columns are memoised. You'd expect that when you runUser.joins(:scores)
again everything is returned from memory without any unnecessary database calls. This isn't the case though. Arel initialises the table again by callingArel::Table#new
and previously cached columns are lost.PS. Sorry for the previous post, formatting went out of control ;)
-
José Valim September 21st, 2010 @ 11:04 AM
- Milestone cleared.
- State changed from new to open
- Assigned user set to Aaron Patterson
- Importance changed from to High
Aaron, could you please take a look? Internet hugs!
-
Repository September 21st, 2010 @ 09:54 PM
- State changed from open to resolved
(from [96bd936b64ae06d4c38e8de862521e22d7c809b9]) providing arel with column information when possible [#5392 state:resolved] http://github.com/rails/rails/commit/96bd936b64ae06d4c38e8de862521e...
-
Repository September 21st, 2010 @ 09:54 PM
(from [a0fc2f7b74e5637b37c66571afe7ca67069d0dda]) providing arel with column information when possible [#5392 state:resolved] http://github.com/rails/rails/commit/a0fc2f7b74e5637b37c66571afe7ca...
-
Jens February 27th, 2011 @ 02:34 PM
Hello,
I'm seeing this again on Rails 3.0.4. It seems for each SQL request, a column definition request is added. (in devel mode, with cache_classes = false)
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1 session2observer at /Users/Jens/Sites/dor-bort/app/controllers/application_controller.rb:138) Continent Load (0.3ms) SELECT "continents".* FROM "continents" SQL (0.6ms) SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull FROM pg_attribute a LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum WHERE a.attrelid = '"continents"'::regclass AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum Thing Load (0.6ms) SELECT "things".* FROM "things" WHERE ("things"."locateable_id" IN (1,2,3,4,5) and "things"."locateable_type" = 'Continent') SQL (0.7ms) SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull FROM pg_attribute a LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum WHERE a.attrelid = '"things"'::regclass AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum Country Load (1.2ms) SELECT "countries".* FROM "countries" WHERE ("countries".continent_id IN (1,2,3,4,5)) SQL (1.0ms) SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull FROM pg_attribute a LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum WHERE a.attrelid = '"countries"'::regclass AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum
-
Paul Gideon Dann March 1st, 2011 @ 11:58 AM
I just discovered the silent-postgres gem, that deals with this problem by silencing those boilerplate lines:
https://github.com/dolzenko/silent-postgres -
Jens March 2nd, 2011 @ 06:09 AM
Well, is it really a good idea to silence these lines, or would the correct way be to prevent those requests from being made?
-
Paul Gideon Dann March 2nd, 2011 @ 09:27 AM
I'm pretty sure those requests are deliberate in development and testing environments. I think it's something to do with the fact that caching is disabled in those environments, so the postgres driver can't assume that the schema won't change. I may have assumed wrong, though. It could be worth playing around with the caching settings, to see if the queries go away.
-
Jens March 2nd, 2011 @ 08:06 PM
Yes, they go away when I set config.cache_classes to true. Also, requests are much faster. So it does seem to be a caching issue.
But IMHO it's also a performance issue, even for development. My example request:
with caching enabled: Completed 200 OK in 436ms (Views: 332.1ms | ActiveRecord: 69.6ms)
without caching: Completed 200 OK in 2257ms (Views: 1146.8ms | ActiveRecord: 875.1ms)
So Rails spends more than ten times as much time with class caching enabled compared to disabled doing database queries?
-
quarterdome May 20th, 2011 @ 06:45 PM
I am seeing this problem in Rails 3.0.6 in production mode with cache_classes=true.
It works fine for the normal rails calls, however I see these table introspection queries for all of my delayed jobs. I did, however, double check that value of cache_classes on delayed jobs is true. Any further pointers to help me investigate what is going on?
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>
People watching this ticket
Referenced by
- 5392 column_definitions method being called before and after every single SQL statement on PostgreSQL (from [96bd936b64ae06d4c38e8de862521e22d7c809b9]) providi...
- 5392 column_definitions method being called before and after every single SQL statement on PostgreSQL (from [a0fc2f7b74e5637b37c66571afe7ca67069d0dda]) providi...
- 4991 Column definitions not cached for calculations on has_many association with :include I'm not sure if it hasn't been already fixed in #5392
- 4991 Column definitions not cached for calculations on has_many association with :include I tested for this behaviour recently with Rails edge. It ...
- 4991 Column definitions not cached for calculations on has_many association with :include Indeed, it looks like it was resolved in #5392