2,296 karma · joined April 14, 2021
I have another article that covers profiling in more detail, you might find it useful: https://death.andgravity.com/fast-conway-cubes#intro-to-prof...
Note that besides the cProfile text output, there are better, graphical tools for profiling; I've personally used pyflame+flamegraph.pl, and tuna.
I gave up because I was too lazy to think how to do the "precompute the maximum +/- error bounds" jiggawatts mentions in https://news.ycombinator.com/item?id=34021826
I ended up not mentioning it because for some reason, it was ~twice as slow on my mac... I'm now curious to try it on a decent Linux machine.
The linked item is to https://blog.mro.name/2022/08/pwned-diy/, where the author converts the passwords list to a CDB (Constant DataBase) file, a simple, fast lookup database format created by D. J. Bernstein.
On my laptop, look `time`s at ~10 ms (for comparison, the Python "binary search" script `time`s at ~50 ms).
* https://scotthelme.co.uk/when-pwned-passwords-bloom/
* https://scotthelme.co.uk/sketchy-pwned-passwords/ – here he uses a count-min sketch to also store the frequency
For some reason, after that, `ls` in that directory (or even shell completion) would freeze the shell entirely, even after reboot. I eventually managed to delete the file with `rm db.sqlite` (no completion allowed), but even that took like 2 minutes.
I might try again with WAL enabled (based on my shell history, I also deleted a -journal file).
Off the top of my head, I don't really know how to do that (aside from the naive way of using threads), I'm guessing readv[1] might be be useful? Will definitely look into it.
Since SQL is ever-so-slightly different across databases, I imagine trying to cover all of them as a single dev is a nightmare (especially if that's not the problem you're trying to solve).
I wrote my own query builder because I know for sure I'm only targeting SQLite. The second I need my feed reader library to work with another database engine I'm dumping my own for something more serious – either a full blown database abstraction layer like SQLAlchemy or Peewee (likely without the ORM part), or something simpler like PyPika or python-sql.[1]
[1]: I talk more about them here: https://death.andgravity.com/own-query-builder#sqlbuilder-py...
(Not that there are lots of other devs on my project at the moment, but)
I am managing this by aggressively limiting the size / features of my query builder, so it's (relatively) easy to understand just by looking at the code.
If it ever passes that point, it's probably time to switch to a "real" query builder / ORM.
Here's the tl;dr of a real-world example[2]:
query = Query().SELECT(...).WHERE(...)
for subtags in tags:
tag_query = BaseQuery({'(': [], ')': ['']}, {'(': 'OR'})
tag_add = partial(tag_query.add, '(')
for subtag in subtags:
tag_add(subtag)
query.WHERE(str(tag_query))
It can be shortened by making a special subclass, but I only needed this once or twice so I didn't bother yet: for subtags in tags:
tag_query = QList('OR')
for subtag in subtags:
tag_query.append(subtag)
query.WHERE(str(tag_query))
[1]: https://death.andgravity.com/query-builder-how#more-init[2]: https://github.com/lemon24/reader/blob/10ccabb9186f531da04db...
Here are two examples:
https://death.andgravity.com/query-builder-why#introspection https://github.com/lemon24/reader/blob/10ccabb9186f531da04db...
data['SELECT'].append('one')
I'm intentionally trying to not depart too much from SQL / list-of-strings-for-each-clause model, since I'd have to invent/learn another one.
For a full-blown query builder, I agree Table("table").select("one") is better.
Alas, SQLite doesn't have them, so query building it is.
In general, SQLAlchemy is an excellent choice; in my specific case (single dev with limited time), the overhead would be too much (even with my previous experience with it).
I talk more about this use case here: https://death.andgravity.com/query-builder-why#the-problem
It likely is.
Ideally, instead of dynamically building queries, one would use stored procedures.
I'm using this with SQLite, which doesn't have stored procedures, so it's an acceptable downgrade for me. Appending strings to lists gets messy quickly, example: https://death.andgravity.com/query-builder-why#preventing-co...
Yup, good thing to note, thank you!
I've kinda assumed everyone knows about the named parameters some bindings offer, but that's probably not true. Will add a disclaimer.
In the previous articles, I do talk about how this is an upgrade from plain SQL, not from regular full-blown query builders / ORMs.