Aaron Patterson's Variety Show!
“I will talk about a variety of things related to puns, Rails, and puns on Rails” —Aaron
https://railsconf.com/2020/video/aaron-patterson-aaron-patterson-s-variety-show
Notes
- #lol “It was very Covid outside” 22:00
- Technical talk starts at 23:58
- This talk is about where clauses
- How they work
- Features you might not know about
- Profiling/speeding up clauses
- Not in your application
- How to speed up Rails itself
- Problem:
Post.where(ActiveRecord::Base.sanitize_sql(["id IN (?)", ids])
is much faster thanPost.where(id: ids)
- Why?
- Aaron benchmarked it.
sanitize_sql
was 74% faster than the simpler API- But something is wrong with the benchmark
- Back to basics
- The
#where
method- Calls are additive:
Post.where(..)
,Post.where(..).where()
- It builds up a SQL statement.
- Calls are additive:
- The
- Something about automatic SQL generation is slower than doing it manually.
Post.all.inspect
adds a LIMIT statement to the end of the queryPost.all.to_a
no LIMITPost.all.inspect
adds “LIMIT 11” to query- ActiveRecord is lazy about generating the query. We need to proactively load the records for the SQL to execute (
Post.where(...).to_a
). - Aaron fixed the benchmark so that each query executed to find 1000 ids.
- New benchmark:
sanitize_sql
statement is still 60% faster.
- New benchmark:
- Back to basics
- Next step: profile the code
- Using StackProf
- Generate two profiles–one for each case.
- Slow case (no_sanitize): 14% querying the database.
- Fast case (sanitize): basically same (20%).
- Speeding up the query method won’t help in this case.
- These profiles tells us how much time we spend in any one particular function call.
- Self vs Self + Children
- What about all of the functions it calls outside of the current method?
- Use
--sort-total
to tell StackProf to sort by the total time spent in a method + any method it calls.
- With
--sort-total
flag, 29% time spent compiling SQL in slow case.- Compiling doesn’t even register in fast case (it’s fast)
- Out target is
Arel::Visitors::ToSql#compile
- Using StackProf
- ActiveRecord Design
- SQL generation involves a few steps:
- Creating Relation Objects
- Each call to
where
, etc. returns a new one - Objects can be reused
- Each call to
- Convert Relation objects into SQL AST
- Tree data structure:
relation.arel.ast
- Graphviz DOT format:
relation.arel.to_dot
- Tree data structure:
- Use DOT command line tool to generate graph:
dot -Tpng -o out.png out.dot
- SQL Generation
- SQL AST -> SQL Statement
- Uses “Vistor” pattern to walk tree
- SQL AST -> SQL Statement
- Creating Relation Objects
- SQL generation involves a few steps:
- Our target is
Arel::Visitors::ToSql#compile
- Something is different in the ASTs that are being generated
- Generate DOT for fast and slow cases
- Auto-sanitized (slow) version very different from
sanitize_sql
(fast) version
- Auto-sanitized (slow) version very different from
- StackProf comparison shows similar results for generating SQL: 28.9% vs. 0.6%
- These number correlate with the ASTs
- How to fix?
- We want to make both methods to work equally
- Reduce the work that the slow case is doing
- Make
where
callsanitize_sql
- #lol 3 refactoring questions:
- Can I refactor this code?
- Should I refactor this code?
- Do I want my name on the blame?
- Aaron contacted Eileen
- There are a number of issues with just calling
sanitize_sql
to generate the query. Non-integer IDS, sanitization, large numbers, etc. - The solution was to create pre-compiled nodes (a new type of node)
- Nodes can be compiled at the
where
callsite, where we know we have a list of IDs. Instead of creating a list of IDs, create a pre-compiled node. - Aaron and Eileen implemented this
- Performance difference
- Their branch is 30% faster than master
- Compare w/ original self-sanitization benchmarks
- Still 1.18x slower (but much better)
- Aaron thinks they can still optimize further to make them equal.
- They call this “Eager Compilation”
- Takeaways:
- Not all code is equal
- Similar behavior should have similar performance
- Poor performance is a bug
- #lol Poor performance? In THIS economy?
0 likes and retweets