1 - while your current select query is reasonably fast, it likely could be faster. It may be that it's taking 0.9 seconds and feels fast, but perhaps it could be 0.09 seconds instead - and that's not something a human can really tell the difference on. It's using an indexed column (status), but it's not a very good index (no offense). There are only a few possible values in 500,000 records, so the index isn't terribly helpful in locating matching records. If possible, you could re-write your perl scripts to do selects and updates using the ID column (primary key), which should be faster than the status column alone. This may be enough to alleviate your locking problem; not sure.

My select query works realy fast. It's not even 0.09 sec. It takes less than 0,01 sec (client shows 0,00), while UPDATE executes 0.33 sec (if I stop all other processes). I know `status` index here isn't very good, but I think 'LIMIT 1' should help here to work faster. I can't use here primary key because of script architecture. Or is there a way of concurrent queue processing, without some kind of status field?


2 - Switch to an InnoDB table, which should allow concurrent SELECT and UPDATE commands. This is a fairly big change if you're not used to InnoDB tables, so read up on this first.

I thought It will be notably slower with InnoDB.


3 - Depending on how you use this table, running OPTIMIZE TABLE periodically may help performance. Updates and deletes on a MyISAM table can cause a fragmented table and poor performance. In my last job I had a table with many thousands of INSERT and subsequent UPDATE operations every day, and it would regularly become fragmented to the point where performance was 1/4 of what it should have been. I started running an OPTIMIZE TABLE command every few hours, took a couple of seconds each time, and performance stayed good.

Thanks for advice. I think I should I give this a try.. :)


Eugene Kosov wrote:
Hi, list!

I have a little table (about 0.5 milloin records) which is kind of queue. My perl script takes records from it one by one and does somes actions.

Here's my table structure:

mysql> desc queue;
+----------------------+---------------------+------+-----+-------------------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------------------+---------------------+------+-----+-------------------+----------------+ | id | int(10) unsigned | | PRI | NULL | auto_increment | | status | tinyint(4) | | MUL | 0 | | | processor_id | int(10) unsigned | YES | MUL | NULL | |
... some other data ...
+----------------------+---------------------+------+-----+-------------------+----------------+



This table, of course, has some indecies:

mysql> show indexes from queue;
+--------------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | +--------------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+ | queue | 0 | PRIMARY | 1 | id | A | 522756 | NULL | NULL | | BTREE | | | queue | 1 | status | 1 | status | A | 3 | NULL | NULL | | BTREE | | | queue | 1 | processor_id | 1 | processor_id | A | 522756 | NULL | NULL | YES | BTREE | | +--------------+------------+--------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+
3 rows in set (0.00 sec)



Perl scripts runs a query like 'UPDATE queue SET status=1, processor_id=XXX WHERE status=0 LIMIT 1'. Whis query shoud (and uses as we can see in following EXPLAIN result) `status` index and work rather fast. But.. It becomes slower and slower. I don't understand why.


mysql> explain select * from certificates where status=0;
+----+-------------+--------------+------+---------------+--------+---------+-------+-------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------------+------+---------------+--------+---------+-------+-------+-------------+ | 1 | SIMPLE | queue | ref | status | status | 1 | const | 52740 | Using where | +----+-------------+--------------+------+---------------+--------+---------+-------+-------+-------------+
1 row in set (0.00 sec)


Despite row numbers to scan (in EXPLAIN results) I think query should work fast because of 'LIMIT 1'. And it works. A query like 'SELECT * FROM queue WHERE status=0 LIMIT 1' works very fast. But in case of update I see that it's not so fast.

mysql> show processlist;
+------+------+-----------+--------------+---------+------+---------------------------+---------------------------------------------------------------------------------------+ | Id | User | Host | db | Command | Time | State | Info | +------+------+-----------+--------------+---------+------+---------------------------+---------------------------------------------------------------------------------------+ | 3257 | root | localhost | certificates | Sleep | 247 | | NULL | | 3261 | root | localhost | certificates | Query | 0 | Locked | SELECT id, domain FROM queue WHERE status='1' AND processor_id='10580' LIMIT 1 | | 3262 | root | localhost | certificates | Query | 1 | Locked | UPDATE queue SET status='1', processor_id='10584' WHERE status='0' LIMIT 1 | | 3263 | root | localhost | certificates | Query | 1 | Locked | SELECT id, domain FROM queue WHERE status='1' AND processor_id='10588' LIMIT 1 | | 3264 | root | localhost | certificates | Query | 1 | Locked | SELECT id, domain FROM queue WHERE status='1' AND processor_id='10590' LIMIT 1 | | 3265 | root | localhost | certificates | Query | 1 | Locked | UPDATE queue SET status='1', processor_id='10592' WHERE status='0' LIMIT 1 | | 3266 | root | localhost | certificates | Query | 1 | Locked | UPDATE queue SET status='1', processor_id='10604' WHERE status='0' LIMIT 1 | | 3267 | root | localhost | certificates | Query | 1 | Locked | UPDATE queue SET status='1', processor_id='10614' WHERE status='0' LIMIT 1 | | 3268 | root | localhost | certificates | Query | 1 | Searching rows for update | UPDATE queue SET status='1', processor_id='10616' WHERE status='0' LIMIT 1 | | 3269 | root | localhost | certificates | Query | 1 | Locked | UPDATE queue SET status='1', processor_id='10618' WHERE status='0' LIMIT 1 | | 3270 | root | localhost | certificates | Query | 1 | Locked | UPDATE queue SET status='1', processor_id='10620' WHERE status='0' LIMIT 1 | | 3271 | root | localhost | certificates | Query | 0 | NULL | show processlist | +------+------+-----------+--------------+---------+------+---------------------------+---------------------------------------------------------------------------------------+
12 rows in set (0.00 sec)

Is it because of index changing after update?
Am I doing something wrong?
Any ideas about how to improve perfomance of this?

Thanks in advance!!


P.S: Size of index is about 10M so it can be loaded into buffer entirely.
mysql> show variables like '%key%';
+--------------------------+------------+
| Variable_name            | Value      |
+--------------------------+------------+
| delay_key_write          | ON         |
| have_rtree_keys          | YES        |
| key_buffer_size          | 20971520   |
| key_cache_age_threshold  | 300        |
| key_cache_block_size     | 1024       |
| key_cache_division_limit | 100        |
| max_seeks_for_key        | 4294967295 |
+--------------------------+------------+
7 rows in set (0.00 sec)








--
MySQL General Mailing List
For list archives: http://lists.mysql.com/mysql
To unsubscribe:    http://lists.mysql.com/[EMAIL PROTECTED]

Reply via email to