4 ms·
I was curious about the performance difference between these shell scripts and sqlite3, single threaded but fast and hardened database. I don't have forever, s
by vessenes 11y ago
I was curious about the performance difference between these shell scripts and sqlite3, single threaded but fast and hardened database.
I don't have forever, so I modified the linked-to scripts to make only 12,345 customer records (two orders of magnitude slower).
I wrote a python importer to sqlite, which is largely CPU bound on the python side -- go would be much faster, but I wanted to stick with his other tools. 20 lines of code.
Times for 'setting up the data': in his case, catting everything into one file. In mine, splitting the data up into rows and inserting into sqlite:
#His Data Prep
time ls | parallel -m -j 32 "cat {} >> ../transactions_cat"
real 0m1.218s
#My Data Prep
time pypy import.py
real 1m54s
#His Count unique products (Note that as written it overcounts)
time cut -d ' ' -f 5- ../transactions_cat | tr -d \" | tr ',' '\n' | parallel --pipe --block 1M sort -u | sort -u | wc -l
real 1m52s
#My Count Unique products
time sqlite3 transaction.db "select count(distinct item) from txs"
real 0m3.033s
#Transactions per day
#(his script -- note that as written it adds up the wrong columns)
real 0m8.976s
#My transactions per day.
time sqlite3 transaction.db ' select substr(date, 1, 10) as day, count(*) from txs group by day'
real 0m8.625s
#Transactions per store month
# I used the single threaded oneliner from the article, he noted it was fastest.
time cut -d ' ' -f 2,3,5 transactions.csv | tr -d '[A-Za-z\"/\- ]' | awk '{print (substr($1,1,5)"-"substr($1,6,6)), length(substr($1,14))+1}' | awk '{a[$1]+=$2;}END{for(i in a)print i" "a[i];}' | sort
real 0m50.886s
#Mine
time sqlite3 transaction.db ' select substr(date, 1, 7) as month, store, count(*) from txs group by month, store'
real 0m16.908s
In each case except for import sqlite is faster. To me the biggest win is not just the speed or the added expressivity (it's a real difference though for many of these queries), but the simplicity with which correctness can be assessed. Two of his three scripts did not do what they said on the tin, and the third one (which seems to), had a large disclaimer on it that he wasn't sure he'd properly optimized it.
- Y0s 11y agoCould you possibly post the importer? I'm interested in replicating/learning from this. Thanks!
- vessenes 11y agoSure. https://gist.github.com/vessenes/1485b5e88e00c898199e https://gist.github.com/vessenes/1485b5e88e00c898199e It's dead simple, though. I'm not sure you'll learn much. :) The three things I did (one for coding simplicity, one for speed and one for correctness): * Used shlex to parse out the quotes and commas in the csv file. shlex seems very slow, anecdotally, and I believe this is most of the time in the import. * I used executemany to do multiple inserts into sqlite. This saves some time because the sqlite module compiles the insert query each time. In my case, I made the simple trade off to do this once per customer file. There's probably some optimal number of lines to use depending on system memory and other configuration knobs, but not worth it in this case to benchmark. * I committed the inserts every hundred customers; in general you don't want a transaction to get too large with most databases, committing will clear that buffer out. I have no idea how performant sqlite is in this case, I just picked a random number for the commits.
- Y0s 11y agoThanks! How did you set up the schema in the sqlite db, as I get the following error on running import.py: sqlite3.OperationalError: no such table: txs
- harperlee 11y agoCome to think of it, it would be an interesting project to implement a basic dbms with sql on top of file management tools.
- justinsaccount 11y agoDid you run those commands on OS X as well? See my other comment above on how the old bsd versions of the text processing tools shipped with OS X are slow.
- vessenes 11y agoI did run them on OS X, with the default tools.