The short answer is that it gets slow. I had heard this before but decided to confirm it with some code. I used SQLite for the database, ActiveRecord to ease the SQL work, and Ruby to automate table generation. Tables of sizes from 100 to 1000 columns and rows were created and populated, and then randomly queried 100 times per benchmark. The benchmarks were averaged and compiled to generate the summary chart. To keep things simple, I only tested a single column of 1000 records, or a single row with 1000 attributes (columns).
require'benchmark'require"./config/environment.rb"ActiveRecord::Base.logger=Logger.new("./log")defdestroy_db`rm "db/halloween_development.sqlite"`enddefmigrate_db`rake db:migrate`enddefbench_the_block(num,&block)Benchmark.bmbmdo|x|x.reportdonum.timesdoblock.callendendendenddefcreate_migrations(num_attribs,model_name)#model name pluralifmodel_name=="candies"`rm "db/migrate/01_create_#{model_name}.rb"`f=File.open("./db/migrate/01_create_#{model_name}.rb","w")else`rm "db/migrate/02_create_#{model_name}.rb"`f=File.open("./db/migrate/02_create_#{model_name}.rb","w")endtable_attributes=""(1..num_attribs).eachdo|num|table_attributes+="t.string :'#{num}'\n"endf.write("""class Create#{model_name.capitalize} < ActiveRecord::Migration def change create_table :#{model_name} do |t|#{table_attributes} end end end """)f.closemigrate_dbenddefpopulate(num_columns,model_name,mode)#model name singularm=Class.const_get(model_name.capitalize)ifmode=="horizontal"m.create("1"=>"x")#House.create("1" => "x")(1..num_columns).eachdo|num|m.find(1).update("#{num}"=>"#{num}")endelsifmode=="vertical"(1..num_columns).eachdo|num|m.create("1"=>"#{num}")endendendnum=1000#number of columns or rowstimes=100#number of times to run the benchmark# destroy_db# create_migrations(num, "houses")#houses# populate(num, "house", "horizontal")# create_migrations(1, "candies")w# populate(num, "candy", "vertical")# puts "Random lookups at #{num} columns"# bench_the_block(times){z=rand(1..num); House.find_by("#{z}"=>z)}# puts "Random lookups at #{num} rows"# bench_the_block(times){Candy.find_by("1" => "#{rand(1..num)}")}
Summary
SQLite3 has a default column limit of 2000! So I wasn’t able to get to the millions of columns I wanted to try. This can be changed but only to about 35k columns. Cursory review of stack overflow indicates that having a database with more than a 100 columns is usually a design flaw with the database.