views:

121

answers:

5

This is part two of the question: http://stackoverflow.com/questions/2913639/mysql-make-this-query-faster-theres-a-way

this query still run slowly:

SELECT b.id,
       b.name,
       c.name
FROM bookcorr as a JOIN books as b on b.id = a.books_id =
JOIN Library as c on c.id = a.library_id 
WHERE a.category_id = '2521' 
AND a.library_id = '4983' 
ORDER BY b.name ASC LIMIT 0,15

Any suggest ?

CREATE TABLE `bookcorr` (
  `category_id` smallint(4) unsigned NOT NULL,
  `book_id` mediumint(7) unsigned NOT NULL,
  `library_id` smallint(5) unsigned NOT NULL,
  UNIQUE KEY `cat_id_3` (`category_id`,`book_id`,`library_id`),
  KEY `category_id` (`category_id`),
  KEY `book_id` (`book_id`),
  KEY `library_id` (`library_id`),
  KEY `cat_id_2` (`cat_id`,`com_id`))

CREATE TABLE `books` (
  `id` mediumint(7) unsigned NOT NULL AUTO_INCREMENT,
  `com_id` smallint(5) unsigned NOT NULL,
  `name` varchar(256) NOT NULL,
    ....
  PRIMARY KEY (`id`),
  KEY `name` (`name`),
  FULLTEXT KEY `search` (`name`,`author`)
)

 CREATE TABLE `Library` (
  `id` smallint(4) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(256) NOT NULL,
  ...
  UNIQUE KEY `id` (`id`),
  KEY `library_name` (`name`)
) 

CREATE TABLE `Category` (
  `id` smallint(4) unsigned NOT NULL,
  `name` varchar(100) NOT NULL,
  UNIQUE KEY `id` (`id`),
  KEY `name` (`name`),
)

Here:

+----+-------------+-------+--------+----------------------------------------+----------+---------+----------------------------+------+-------------+
| id | select_type | table | type   | possible_keys                          | key      | key_len | ref                        | rows | Extra       |
+----+-------------+-------+--------+----------------------------------------+----------+---------+----------------------------+------+-------------+
|  1 | SIMPLE      | b     | index  | NULL                                   | name     | 258     | NULL                       |   15 |             |
|  1 | SIMPLE      | a     | eq_ref | cat_id_3,cat_id,book_id,library_id     | cat_id_3 | 7       | const,b.id,const           |    1 | Using index |
|  1 | SIMPLE      | c     | const  | PRIMARY                                | PRIMARY  | 2       | const                      |    1 | Using where |
+----+-------------+-------+--------+----------------------------------------+----------+---------+----------------------------+------+-------------+
A: 
SELECT  b.id,
        b.name,
        c.name
FROM    books as b
JOIN    bookcorr as a
ON      a.books_id = b.id
        AND a.category_id = '2521' 
        AND a.library_id = '4983' 
JOIN    Library as c
ON      c.id = a.library_id 
ORDER BY
        b.name ASC
LIMIT 15

Create the following indexes:

books (name)
bookcorr (category_id, library_id, books_id)

Update:

If you need the total record count, it would be better doing it in two queries.

Assuming that books_id and library_id always reference a record in books and library, use this query:

SELECT  COUNT(*)
FROM    bookcorr a
WHERE   a.category_id = '2521'
        AND a.library_id = '4983' 

to calculate the count.

Update 2:

SELECT  b.id,
        b.name,
        c.name
FROM    books b USE INDEX (name)
STRAIGHT_JOIN
        bookcorr a
ON      a.books_id = b.id
        AND a.category_id = '2521' 
        AND a.library_id = '4983' 
STRAIGHT_JOIN
        Library as c
ON      c.id = a.library_id 
ORDER BY
        b.name ASC
LIMIT 15
Quassnoi
There's a problem.... i'v put SQL_CALC_FOUND_ROWS after the select because i need to know the number of results for pagination. After that the query is SLOWER than before...
robert
@robert: this query is optimized for `LIMIT`, so adding `SQL_CALC_FOUND_ROWS` will make it slower of course.
Quassnoi
ok i'v removed the SQL_CALC but the query still run slowly... about 4 seconds... :(
robert
Is the plan without `CALC` the same?
Quassnoi
Yes, its seems to be slower than before...
robert
@robert: did you create the indexes I suggested? Could you please post result of `SHOW CREATE TABLE …` for all relevant tables?
Quassnoi
@robert: try the updated query and post its plan.
Quassnoi
Not so good results in > 0,6 sec, I cant understand why
robert
With different category_id and library_id iv got results in 3,4 sec :-(
robert
@robert: please post the plan
Quassnoi
@robert: this plan is exactly as it should be. How many records do you have in each of the tables? How long does the query take on a hot cache (after you run it several times)?
Quassnoi
@robert: BTW, is `books` `MyISAM` or `InnoDB`?
Quassnoi
The books table is about 2,5 million entries, after the first query, the cache is obiviusly fast... MyISAM
robert
@robert: I don't mean the query cache, I mean the key cache. You should disable the query cache for testing with `SQL_NO_CACHE` for testing purposes. What does your count query return you?
Quassnoi
@robert: `SELECT COUNT(*) FROM bookcorr a WHERE a.category_id = '2521' AND a.library_id = '4983'`
Quassnoi
The count is 1722
robert
@robert: ah, I see. You have an index on `bookcorr (category_id, book_id, library_id)`, but you need an index on `bookcorr (category_id, library_id, book_id)` (in this order). Create this index and run your **original** query.
Quassnoi
Done, i'v delete the first index and created the new one. The first query for the 1st page (15 results) is slow (3,4sec) but when i go on to the next page is very fast, but the first one is always slow.
robert
The Cardinality is 0 for category_id and library_id, is it ok ?
robert
@robert: could you please post the plan with the new index?
Quassnoi
+1  A: 

Looks like you need to study how to use "explain select".

It will make all your queries faster! :)

ceteras
A: 

Add a books_id index in bookcorr table.If the query stills slow, try to use numerical ids for the books(Integer).

Marcos Perez
A: 

mysql> explain SELECT b.id,b.name,c.name FROM bookcorr as a JOIN books as b on a.book_id = b.id JOIN library as c on b.library_id=c.id WHERE a.category_id = '2302' AND a.library_id = '4983' order by b.name asc LIMIT 0,15;

+----+-------------+-------+--------+----------------------------------------+----------+---------+--------------------+------+----------------------------------------------+
| id | select_type | table | type   | possible_keys                          | key      | key_len | ref                | rows | Extra                                        |
+----+-------------+-------+--------+----------------------------------------+----------+---------+--------------------+------+----------------------------------------------+
|  1 | SIMPLE      | a     | ref    | cat_id_3,cat_id,book_id,library_id     | cat_id_3 | 4       | const,const        | 1788 | Using index; Using temporary; Using filesort |
|  1 | SIMPLE      | b     | eq_ref | PRIMARY,library_id                     | PRIMARY  | 3       | dbname.a.book_id   |    1 |                                              |
|  1 | SIMPLE      | c     | eq_ref | PRIMARY                                | PRIMARY  | 2       | dbname.b.library_id|    1 |                                              |
+----+-------------+-------+--------+----------------------------------------+----------+---------+--------------------+------+----------------------------------------------+
robert
Quassnoi I'm user registered now, please reply here thanks
robert
The first query takes 3.35 sec, the next pages 0,01 sec
robert
A: 

Is it a typo or why in the original query the SQL like that (?):

JOIN books as b on b.id = a.books_id = JOIN Library as c on c.id = a.library_id
Andy
Yes, is a typo !
robert