Last active
January 12, 2025 19:58
-
-
Save alekseyl/5d08782808a29df6813f16965f70228a to your computer and use it in GitHub Desktop.
nested_select_profiling
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This is a simple gist for performance and RAM usage testing for a nested_select gem | |
# | |
# Objects relations: course -> topics -> lessons ( all relations are has_many ) | |
# | |
# ------------------------------------------------------------------------- | |
# Schemas: | |
# | |
# create_table "lessons", force: :cascade do |t| | |
# t.string "title", null: false, comment: "Тема урока" | |
# t.string "description", null: false, comment: "Описание урока" | |
# t.integer "topic_id", null: false | |
# t.datetime "created_at", precision: 6, null: false | |
# t.datetime "updated_at", precision: 6, null: false | |
# t.integer "partition", default: 1, null: false | |
# t.integer "position", default: 0 | |
# t.integer "parent_id", default: 0 | |
# t.integer "education_year" | |
# t.text "text" | |
# t.boolean "actived", default: true | |
# t.boolean "is_public", default: false | |
# t.boolean "online", default: false | |
# t.datetime "deleted_at" | |
# t.integer "kind" | |
# t.string "recording_link" | |
# t.jsonb "body" | |
# t.datetime "content_updated_at" | |
# t.index ["content_updated_at"], name: "index_lessons_on_content_updated_at", where: "(content_updated_at IS NOT NULL)" | |
# t.index ["topic_id"], name: "index_lessons_on_topic_id" | |
# end | |
# | |
# create_table "topics", force: :cascade do |t| | |
# t.string "title", null: false, comment: "Тема модуля" | |
# t.string "description", null: false, comment: "Описание модуля" | |
# t.integer "course_id", null: false | |
# t.datetime "created_at", precision: 6, null: false | |
# t.datetime "updated_at", precision: 6, null: false | |
# t.integer "partition", default: 1, null: false | |
# t.integer "position", default: 0 | |
# t.boolean "free" | |
# t.datetime "deleted_at" | |
# t.integer "kind" | |
# t.integer "lessons_count", default: 0, null: false | |
# t.index "to_tsvector('russian'::regconfig, (title)::text)", name: "gin_index_topics_on_title", using: :gin | |
# t.index ["course_id"], name: "index_topics_on_course_id" | |
# end | |
# | |
# ------------------------------------------------------------------------- | |
# | |
# Rem: Outside of this method I have preselected a set of course ids, and providing them via root_ids attribute | |
# | |
require 'nested_select' | |
def compare_nested_select( root_ids, root_collection_size, silence_ar_logger_for_memory_profiling: true) | |
puts "\n------- CPU comparison, for root_collection_size: #{root_collection_size} ----" | |
ActiveRecord::Base.logger.silence do | |
Benchmark.bm do |benchmark| | |
benchmark.report("nested_select") do | |
50.times do | |
Topic.where(course_id: root_ids.sample(root_collection_size)).includes(:lessons) | |
.select(:id, :position, :title, :course_id, lessons: [:id, :title, :topic_id, :position]).load | |
end | |
end | |
benchmark.report("simple includes") do | |
50.times do | |
Topic.where(course_id: root_ids.sample(root_collection_size)).includes(:lessons) | |
.select(:id, :position, :title, :course_id,).load | |
end | |
end | |
end | |
end | |
puts "\n----------------- Memory comparison, for root_collection_size: #{root_collection_size} ---------" | |
ids_sample = root_ids.sample(root_collection_size) # it should be the same id for both tests, since we comparing memory consumption | |
ActiveRecord::Base.logger.level = :error if silence_ar_logger_for_memory_profiling | |
ns = MemoryProfiler.report do | |
Topic.where(course_id: ids_sample) | |
.includes(:lessons) | |
.select(:id, :position, :title, :course_id, lessons: [:id, :title, :topic_id, :position]).load | |
end | |
direct_include = MemoryProfiler.report do | |
Topic.where(course_id: ids_sample).select(:id, :position, :title, :course_id,).includes(:lessons).load | |
end | |
ActiveRecord::Base.logger.level = :debug if silence_ar_logger_for_memory_profiling | |
puts "------ Nested Select memory consumption for root_collection_size: #{root_collection_size} ------" | |
ns.pretty_print(detailed_report: false, scale_bytes: true) | |
puts "------ Full preloading memory consumption for root_collection_size: #{root_collection_size} ----" | |
direct_include.pretty_print(detailed_report: false, scale_bytes: true) | |
puts "RAM ratio improvements x#{direct_include.total_retained_memsize.to_f / ns.total_retained_memsize} on retain objects" | |
puts "RAM ratio improvements x#{direct_include.total_allocated_memsize.to_f / ns.total_allocated_memsize} on total_allocated objects" | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment