4

My Query:

SELECT * FROM privatemessages69 
WHERE sender='19' OR recipient='19' 
ORDER BY id DESC;

My Table:

CREATE TABLE `privatemessages69` (
  `id` int(11) NOT NULL auto_increment,
  `recipient` int(11) NOT NULL,
  `sender` int(11) NOT NULL,
  `time` int(11) NOT NULL,
  `readstatus` int(11) NOT NULL,
  `message` varchar(255) NOT NULL,
  `messagetype` int(11) NOT NULL,
  `rdeleted` int(11) NOT NULL,
  `sdeleted` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  KEY `msgpanel` (`sender`,`recipient`,`id`)
) ENGINE=InnoDB AUTO_INCREMENT=50000 DEFAULT CHARSET=latin1

Explain:

mysql> explain SELECT * FROM privatemessages69 WHERE sender='19' OR recipient='19' ORDER BY id DESC;
+----+-------------+-------------------+-------+---------------+---------+---------+------+-------+-------------+
| id | select_type | table             | type  | possible_keys | key     | key_len | ref  | rows  | Extra       |
+----+-------------+-------------------+-------+---------------+---------+---------+------+-------+-------------+
|  1 | SIMPLE      | privatemessages69 | index | msgpanel      | PRIMARY | 4       | NULL | 50191 | Using where |
+----+-------------+-------------------+-------+---------------+---------+---------+------+-------+-------------+
1 row in set (0.00 sec)

Can someone tell me the correct way of indexing this table for that query? If I remove the order by, type goes to ALL.

Thanks for any help

3 Answers 3

3

Having one index on sender and one on recipient should be enough for such a query:

CREATE INDEX ind_sender
    ON privatemessages69 (sender) ;

CREATE INDEX ind_recipient 
    ON privatemessages69 (recipient) ;

And I don't think it's going to be faster if you write it using UNION.


You can also try adding these two indexes (and removing the above ones):

CREATE INDEX ind_sender_2
    ON privatemessages69 (sender, id) ;

CREATE INDEX ind_recipient_2
    ON privatemessages69 (recipient, id) ;

I can't test now but it may get rid of the filesort.


You can still edit your question and add at the end:

  • Time with ORDER BY: (3-4 seconds as you say)
  • Number of total rows in the table:
  • Number of rows with recipient=19:
  • Number of rows with sender=19:
  • Number of rows the query returns:

Some tests I did yesterday with about 300 thousand total rows showed the query running in less than a second. The slowness maybe due to configuration settings of MySQL.

Also: Does the query takes 3-4 seconds whatever you put (instead of 19)?

Sign up to request clarification or add additional context in comments.

1 Comment

This definitely seems to be the fastest way of doing it. I guess the only real problem i'm having now is ORDER BY slowing down the query. Do you know of a good solution for speeding that up? (Should I ask this as a new question? New Here) Thank you for the help!
2

You can't index the table for that query, but here is an another one that will run fast, if you put 2 distinct indexes on sender and recipient:

SELECT * FROM (
    SELECT * FROM privatemessages69 WHERE sender=19
    UNION
    SELECT * FROM privatemessages69 WHERE recipient=19
) t
ORDER BY id DESC;

11 Comments

Any reference to why that is?
@Kevin Peno: Mysql cannot make use of an index spanning 2 two columns, if both columns are combined using OR. Have a look at the mysql documentation explaining index usage (last example box): dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html
@soulmerge, if you add a seperate index on recipient, then you can use the select * from privatemessages69 where sender = 19 or recipient = 19 and it will use and index on both. if you do not alter the table and thus do not add an index your code will not use an index on recipient because it is not the left-most part of a composite index, so how is your code better than using a simple OR ?
@soulmerge: You are (or I should say MySQL's online documentation is) wrong in that point. Two (or more) indexes on two (or more) separate fields can be used with OR, exactly as Brian's query. The version i checked (5.0.51) shows type: index_merge in the EXPLAIN.
|
1

I believe you would need to write an index where both columns have the first position. In your case adding:

CREATE INDEX `msgpanel_recp` ON `privatemessages69` (`recipient`,`id`)

1 Comment

This is using type:all when ORDER BY is removed from the query

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.