zulip/zerver/lib
Steve Howell 8cc82c6cbe Optimize /json/update_message_flags.
I added filter() statements to do_update_message_flags().

Here is some context:

Steve Howell: Case 1, have AND clause to reduce work for DB.

humbug=> update zerver_usermessage set flags = (flags & ~1) where id > 9000;
UPDATE 382
humbug=> select count(*) from zerver_usermessage where (flags & 1) = 0;
 count
-------
   382
(1 row)

humbug=> explain analyze update zerver_usermessage set flags = (flags | 1) where (flags & 1) = 0;
                                                       QUERY PLAN
------------------------------------------------------------------------------------------------------------------------
 Update on zerver_usermessage  (cost=0.00..266.85 rows=47 width=27) (actual time=5.727..5.727 rows=0 loops=1)
   ->  Seq Scan on zerver_usermessage  (cost=0.00..266.85 rows=47 width=27) (actual time=0.045..2.751 rows=382 loops=1)
         Filter: ((flags & 1::bigint) = 0)
         Rows Removed by Filter: 9000
 Total runtime: 5.759 ms
(5 rows)

humbug=> select count(*) from zerver_usermessage where (flags & 1) = 0;
 count
-------
     0
(1 row)
Leo Franchi: Sounds reasonable, but I know way less than zev about DBs so I'll defer to his judgement :)

Steve Howell: Case 2, how the code works now:

humbug=> update zerver_usermessage set flags = (flags & ~1) where id > 9000;
UPDATE 382
humbug=> select count(*) from zerver_usermessage where (flags & 1) = 0;
 count
-------
   382
(1 row)

humbug=> explain analyze update zerver_usermessage set flags = (flags | 1);
                                                        QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------
 Update on zerver_usermessage  (cost=0.00..243.28 rows=9382 width=27) (actual time=362.075..362.075 rows=0 loops=1)
   ->  Seq Scan on zerver_usermessage  (cost=0.00..243.28 rows=9382 width=27) (actual time=0.008..6.138 rows=9382 loops=1)
 Total runtime: 362.105 ms
(3 rows)

humbug=> select count(*) from zerver_usermessage where (flags & 1) = 0;
 count
-------
     0
(1 row)
Steve Howell: In both trials, we set it up so that only 382 of 9382 rows need to be updated. The first trial runs about 63x as fast. The second trial, if my theory is correct, is doing 24x as many writes as it needs. Both trials are reading all 9382 rows.

Steve Howell: The expense of the update statement seems to be proportional to the number of rows you "update", not the number of rows that you actually change.

Steve Howell: For now I created #1869.

Zev Benjamin: That sounds like a reasonable explanation. The disk IO can be expensive

(imported from commit d9090daee1f81cad76c430de0956f9bd504da075)
2013-10-15 11:30:13 -04:00
..
bugdown Parse markdown tables and show them with some styling 2013-10-10 16:39:11 -04:00
__init__.py [manual] Rename Django app from zephyr to zerver. 2013-08-06 07:39:36 -04:00
actions.py Optimize /json/update_message_flags. 2013-10-15 11:30:13 -04:00
alert_words.py Pre-fetch data from the DB and hand to markdown thread 2013-10-10 10:58:21 -04:00
avatar.py Extract get_avatar_url(). 2013-09-30 18:22:06 -04:00
bulk_create.py Make populate_db set the is_bot flag on bot accounts. 2013-09-18 16:16:17 -04:00
cache.py Don't cache UserPresence info. 2013-09-17 14:51:56 -04:00
cache_helpers.py Don't cache UserPresence info. 2013-09-17 14:51:56 -04:00
ccache.py Add webathena authentication button for Zephyr users. 2013-08-26 18:17:25 -04:00
context_managers.py [manual] Rename Django app from zephyr to zerver. 2013-08-06 07:39:36 -04:00
create_user.py New onboarding step: Set up an integration. 2013-08-08 17:23:27 -04:00
debug.py [manual] Rename Django app from zephyr to zerver. 2013-08-06 07:39:36 -04:00
event_queue.py Let clients specify how long queues shall live, within limits 2013-08-20 16:19:07 -04:00
html_diff.py [manual] Rename Django app from zephyr to zerver. 2013-08-06 07:39:36 -04:00
initial_password.py [manual] Rename Django app from zephyr to zerver. 2013-08-06 07:39:36 -04:00
logging_util.py Change Humbug => Zulip in name of error limiter module. 2013-08-07 10:00:07 -04:00
mandrill_client.py Add Mandrill decorators, credentials, actions 2013-10-10 19:32:21 -04:00
mention.py Pre-fetch data from the DB and hand to markdown thread 2013-10-10 10:58:21 -04:00
parallel.py [manual] Rename Django app from zephyr to zerver. 2013-08-06 07:39:36 -04:00
query.py [manual] Rename Django app from zephyr to zerver. 2013-08-06 07:39:36 -04:00
queue.py Fix parameters for on_close callback 2013-10-09 10:45:38 -04:00
rate_limiter.py [manual] Rename Django app from zephyr to zerver. 2013-08-06 07:39:36 -04:00
response.py [manual] Rename Django app from zephyr to zerver. 2013-08-06 07:39:36 -04:00
timeout.py [manual] Rename Django app from zephyr to zerver. 2013-08-06 07:39:36 -04:00
timestamp.py [manual] Rename Django app from zephyr to zerver. 2013-08-06 07:39:36 -04:00
tornado_ioloop_logging.py [manual] Rename Django app from zephyr to zerver. 2013-08-06 07:39:36 -04:00
unminify.py [manual] Rename Django app from zephyr to zerver. 2013-08-06 07:39:36 -04:00
upload.py uploads: have upload_image_to_s3 take file data instead of a file object. 2013-09-17 10:00:01 -04:00
utils.py Move to a common random token generation function instead of several one-offs. 2013-08-09 14:59:26 -04:00