简体   繁体   中英

Optimize a query

How can I proceed to make my response time more faster, approximately the average time of response is 0.2s ( 8039 records in my items table & 81 records in my tracking table )

Query

 SELECT a.name, b.cnt  FROM `items` a  LEFT JOIN 
(SELECT guid, COUNT(*) cnt FROM tracking WHERE
date > UNIX_TIMESTAMP(NOW() - INTERVAL 1 day ) GROUP BY guid)  b ON
a.`id` = b.guid WHERE a.`type` = 'streaming' AND a.`state` = 1 
ORDER BY b.cnt DESC LIMIT 15 OFFSET 75

Tracking table structure

CREATE TABLE `tracking` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`guid` int(11) DEFAULT NULL,
`ip` int(11) NOT NULL,
`date` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `i1` (`ip`,`guid`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4303 DEFAULT CHARSET=latin1;

Items table structure

CREATE TABLE `items` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`guid` int(11) DEFAULT NULL,
`type` varchar(255) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`embed` varchar(255) DEFAULT NULL,
`url` varchar(255) DEFAULT NULL,
`description` text,
`tags` varchar(255) DEFAULT NULL,
`date` int(11) DEFAULT NULL,
`vote_val_total` float DEFAULT '0',
`vote_total` float(11,0) DEFAULT '0',
`rate` float DEFAULT '0',
`icon` text CHARACTER SET ascii,
`state` int(11) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9258 DEFAULT CHARSET=latin1;

Your query, as written, doesn't make much sense. It produces all possible combinations of rows in your two tables and then groups them.

You may want this:

    SELECT a.*, b.cnt 
      FROM `items` a  
 LEFT JOIN (
              SELECT guid, COUNT(*) cnt 
                FROM tracking 
               WHERE `date` > UNIX_TIMESTAMP(NOW() - INTERVAL 1 day) 
            GROUP BY guid
           )  b ON a.guid = b.guid
  ORDER BY b.cnt DESC

The high-volume data in this query come from the relatively large tracking table. So, you should add a compound index to it, using the columns (date, guid) . This will allow your query to random-access the index by date and then scan it for guid values.

 ALTER TABLE tracking ADD INDEX guid_summary (`date`, guid);

I suppose you'll see a nice performance improvement.

Pro tip: Don't use SELECT * . Instead, give a list of the columns you want in your result set. For example,

SELECT a.guid, a.name, a.description, b.cnt  

Why is this important?

First, it makes your software more resilient against somebody adding columns to your tables in the future.

Second, it tells the MySQL server to sling around only the information you want. That can improve performance really dramatically, especially when your tables get big.

Since tracking has significantly fewer rows than items , I will propose the following.

SELECT  i.name, c.cnt
    FROM  
    (
        SELECT  guid, COUNT(*) cnt
            FROM  tracking
            WHERE  date > UNIX_TIMESTAMP(NOW() - INTERVAL 1 day )
            GROUP BY  guid 
    ) AS c
    JOIN  items AS i  ON i.id = c.guid
    WHERE  i.type = 'streaming'
      AND  i.state = 1;
    ORDER BY  c.cnt DESC
    LIMIT  15 OFFSET 75

It will fail to display any items for which cnt is 0. (Your version displays the items with NULL for the count.)

Composite indexes needed:

items: The PRIMARY KEY(id) is sufficient.
tracking: INDEX(date, guid) -- "covering"

Other issues:

  • If ip is an IP-address, it needs to be INT UNSIGNED . But that covers only IPv4, not IPv6.
  • It seems like date is not just a "date", but really a date+time. Please rename it to avoid confusion.
  • float(11,0) -- Don't use FLOAT for integers. Don't use (m,n) on FLOAT or DOUBLE . INT UNSIGNED makes more sense here.

OFFSET is naughty when it comes to performance -- it must scan over the skipped records. But, in your query, there is no way to avoid collecting all the possible rows, sorting them, stepping over 75, and only finally delivering 15 rows. (And, with no more than 81, it won't be a full 15.)

What version are you using? There have been important changes to the Optimization of LEFT JOIN ( SELECT ... ) . Please provide EXPLAIN SELECT for each query under discussion.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM