indexed_table
Задача десять раз решена создателями СУБД, соответственно, я написал in-memory таблицу с индексами. Свое красно-черное дерево писать не стал, взял гем rbtree, написал простенький DSL для создания запросов (его возможности ограничены возможностями backing container, если взять TreeMap из Явы, то можно было бы реализовать операторы "строго больше" и "строго меньше"). Индекс берется первый подходящий, если нет ни одного индекса, полностью подходящего для выполнения запроса, то сразу table scan. Все это дело достаточно хрупкое (тестовое задание, все-таки).
Использование
В Gemfile добавить gem "indexed_table", :git => "git://github.com/PavelPenkov/indexed_table.git"
или скачать, собрать и поставить.
require 'indexed_table'
table = Table.new
table.create_index :x, :y
100.times do |i|
100.times do |j|
table.insert({:x => i, :y => j})
end
end
res = table.query do # will use index
y <= 42
x >= 42
end
res = table.query { x == 42 } # will use index
res = table.query { y == 42 } # will use table scan
Тесты
Все, кроме производительности rake spec
Все, включая производительность perf=1 rake spec
Производительность
(на дохлой виртуалке)
Insert without index: 0.007338149
Query without index: 4.524136761
Query without index 2 conditions: 5.715206423
Raw iteration: 0.864453755
Insert with simple index: 0.161951593
Query with simple index: 0.00581417
Insert with composite index: 0.573067718
Query composite index 2 conditions: 0.534834588
Query composite index first part condition: 0.011736373