Skip to content

Instantly share code, notes, and snippets.

@mbj
Created December 2, 2011 19:14
Show Gist options
  • Save mbj/1424460 to your computer and use it in GitHub Desktop.
Save mbj/1424460 to your computer and use it in GitHub Desktop.
DataMapper loads far to much records when saving a child with multiple parents.
DM_VERSION = '1.3.0.beta'
%w(core migrations types aggregates timestamps validations sqlite-adapter do-adapter).each do |name|
if name == 'validations' && ENV['WITHOUT_BREAKING_COMMIT']
gem 'dm-validations', DM_VERSION, :git => 'git://github.com/mbj/dm-validations', :branch => 'test/without-breaking-commit'
else
gem "dm-#{name}", DM_VERSION, :git => "git://github.com/datamapper/dm-#{name}.git"
end
end
~ (0.000090) SELECT sqlite_version(*)
~ (0.000188) DROP TABLE IF EXISTS "manufacturers"
~ (0.000032) PRAGMA table_info("manufacturers")
~ (0.000355) CREATE TABLE "manufacturers" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "name" VARCHAR(50))
~ (0.000032) DROP TABLE IF EXISTS "product_sources"
~ (0.000021) PRAGMA table_info("product_sources")
~ (0.000146) CREATE TABLE "product_sources" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "name" VARCHAR(50))
~ (0.000073) DROP TABLE IF EXISTS "products"
~ (0.000020) PRAGMA table_info("products")
~ (0.000136) CREATE TABLE "products" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "name" VARCHAR(50), "product_source_id" INTEGER NOT NULL, "manufacturer_id" INTEGER)
~ (0.000124) CREATE INDEX "index_products_product_source" ON "products" ("product_source_id")
~ (0.000097) CREATE INDEX "index_products_manufacturer" ON "products" ("manufacturer_id")
~ (0.000055) INSERT INTO "product_sources" ("name") VALUES ('Source')
~ (0.000051) SELECT "id", "name", "product_source_id", "manufacturer_id" FROM "products" WHERE "product_source_id" = 1 ORDER BY "id"
~ (0.000065) INSERT INTO "products" ("name", "product_source_id") VALUES ('Product A', 1)
~ (0.000065) INSERT INTO "products" ("name", "product_source_id") VALUES ('Product B', 1)
~ (0.000062) INSERT INTO "products" ("name", "product_source_id") VALUES ('Product C', 1)
~ (0.000039) SELECT "id", "name" FROM "product_sources" WHERE "id" = 1 LIMIT 1
~ (0.000050) SELECT "id", "name", "product_source_id", "manufacturer_id" FROM "products" WHERE ("product_source_id" = 1 AND "name" = 'Product A') ORDER BY "id" LIMIT 1
==============================================
BAD BOY FOLLOWS SELECTS 50K records in my case
==============================================
~ (0.000045) SELECT "id", "name", "product_source_id", "manufacturer_id" FROM "products" WHERE "product_source_id" = 1 ORDER BY "id"
~ (0.000053) UPDATE "products" SET "name" = 'Test' WHERE "id" = 1
~ (0.000101) SELECT sqlite_version(*)
~ (0.000165) DROP TABLE IF EXISTS "manufacturers"
~ (0.000030) PRAGMA table_info("manufacturers")
~ (0.000363) CREATE TABLE "manufacturers" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "name" VARCHAR(50))
~ (0.000027) DROP TABLE IF EXISTS "product_sources"
~ (0.000023) PRAGMA table_info("product_sources")
~ (0.000280) CREATE TABLE "product_sources" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "name" VARCHAR(50))
~ (0.000050) DROP TABLE IF EXISTS "products"
~ (0.000017) PRAGMA table_info("products")
~ (0.000133) CREATE TABLE "products" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "name" VARCHAR(50), "product_source_id" INTEGER NOT NULL, "manufacturer_id" INTEGER)
~ (0.000110) CREATE INDEX "index_products_product_source" ON "products" ("product_source_id")
~ (0.000083) CREATE INDEX "index_products_manufacturer" ON "products" ("manufacturer_id")
~ (0.000058) INSERT INTO "product_sources" ("name") VALUES ('Source')
~ (0.000052) SELECT "id", "name", "product_source_id", "manufacturer_id" FROM "products" WHERE "product_source_id" = 1 ORDER BY "id"
~ (0.000062) INSERT INTO "products" ("name", "product_source_id") VALUES ('Product A', 1)
~ (0.000059) INSERT INTO "products" ("name", "product_source_id") VALUES ('Product B', 1)
~ (0.000059) INSERT INTO "products" ("name", "product_source_id") VALUES ('Product C', 1)
~ (0.000036) SELECT "id", "name" FROM "product_sources" WHERE "id" = 1 LIMIT 1
~ (0.000047) SELECT "id", "name", "product_source_id", "manufacturer_id" FROM "products" WHERE ("product_source_id" = 1 AND "name" = 'Product A') ORDER BY "id" LIMIT 1
~ (0.000043) SELECT "id", "name", "product_source_id", "manufacturer_id" FROM "products" WHERE "product_source_id" = 1 ORDER BY "id"
~ (0.000059) UPDATE "products" SET "name" = 'Test' WHERE "id" = 1
require 'logger'
require 'dm-core'
require 'dm-validations'
require 'dm-migrations'
# Note: if you remove the Manufacturer the bug dissappears!
class Manufacturer
include DataMapper::Resource
property :id,Serial
property :name,String
has n,:products
end
class ProductSource
include DataMapper::Resource
property :id,Serial
property :name,String
has n,:products
end
class Product
include DataMapper::Resource
property :id,Serial
property :name,String
belongs_to :product_source
belongs_to :manufacturer, :required => false
end
DataMapper::Logger.new($stdout,:debug)
DataMapper.finalize
DataMapper.setup(:default,'sqlite::memory:')
DataMapper.auto_migrate!
product_source = ProductSource.create(:name => 'Source')
product_source.products.create :name => 'Product A'
product_source.products.create :name => 'Product B'
product_source.products.create :name => 'Product C'
# Make sure childs are not cached!
product_source = ProductSource.get(product_source.id)
product = product_source.products.first(:name => 'Product A')
# This call results in:
# ~ (0.000108) SELECT "id", "name", "product_source_id", "manufacturer_id" FROM "products" WHERE "product_source_id" = 1 ORDER BY "id" # <<- THIS IS HTE BAD ONE
# ~ (0.000078) UPDATE "products" SET "name" = 'Test' WHERE "id" = 1
#
product.update(:name => 'Test')
@mbj
Copy link
Author

mbj commented Dec 2, 2011

@emmanuel you might be interested in this! The dm-validations commit I complained about is involved!

@mbj
Copy link
Author

mbj commented Dec 2, 2011

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment