Why does ActiveRecord provide .delete_all and not .truncate?
It seems strange that I have to manually execute SQL to use the TRUNCATE command. Is there something bad about it that DHH is p开发者_StackOverflowrotecting me against?
Using TRUNCATE
on some databases does not run triggers. Using DELETE
for each row will still run triggers. TRUNCATE
also cannot be rolled back, so if you did a .destroy_all
in a transaction, it would erase all the data even if you tried to rollback.
So, yes, you are being protected against the effects of truncate.
Assuming you're using MySQL or Postgre and not SQlite3 (which doesn't support TRUNCATE
), you could add the following method to your model.
def self.truncate
self.connection_pool.with_connection { |c| c.truncate(table_name) }
end
Note that this would not invoke ActiveRecord callbacks. There are better ways to do this that don't tie your code to a specific DB implementation, but even this is better than writing the SQL yourself.
There are many use cases for TRUNCATE
, and in my opinion, the answers given here are very insufficient. Using Postgres as an example:
TRUNCATE
is definitely transaction safe in some RDBMS, as already noted by jsears. It can be rolled back, at least in Postgres. Isn't Rails supposed to be db-agnostic and allow for such things?TRUNCATE
will also executeBEFORE TRUNCATE
orAFTER TRUNCATE
triggers in Postgres. If you are expecting aDELETE
trigger to fire onTRUNCATE
that's your design fault!TRUNCATE
performs far quicker thanDELETE
especially for large datasets because it's a single short DDL statement.- In Postgres' MVCC architecture,
TRUNCATE
removes all index and table bloat.
For these reasons it's crazy to me that Rails does not support TRUNCATE
. No, I don't think the reasons given are good ones.
Take a look at Model.destroy_all and active record : dependent => :destroy relations. If you don't specify :dependent => :destory, some of the defaults is to set relation to null but not destroy the record.
精彩评论