jpyeron@stripped wrote on 08/01/2005 09:13:46 AM:
> I have this query which gets executed often, but when I saw this today I
> panicked. Any suggestions to why this took so long?
>
> mysql> SELECT t2.id, t2.bdate, t2.level FROM bvolset AS t1 JOIN bvolset
AS
> t2 ON t2.bdate<t1.bdate AND t2.level<t1.level WHERE t1.id=30 ORDER BY
> bdate DESC LIMIT 1;
>
> Empty set (22.82 sec)
>
> here is the schema and data:
>
> CREATE TABLE bvolset (
> id int(11) NOT NULL auto_increment,
> bdate datetime default NULL,
> level int(11) NOT NULL default '0',
> PRIMARY KEY (id),
> UNIQUE KEY bdate (bdate),
> KEY level (level)
> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
>
>
>
> INSERT INTO `bvolset` VALUES (1,'2005-07-05 00:00:00',0),
> (15,'2005-01-01 00:00:00',3),(16,'2005-01-02 00:00:00',4),
> (17,'2005-01-03 00:00:00',3),(18,'2005-01-04 00:00:00',2),
> (19,'2005-01-05 00:00:00',3),(20,'2005-01-06 00:00:00',4),
> (21,'2005-01-07 00:00:00',3),(22,'2005-01-08 00:00:00',1),
> (23,'2005-01-09 00:00:00',3),(24,'2005-01-10 00:00:00',4),
> (25,'2005-01-11 00:00:00',3),(26,'2005-01-12 00:00:00',2),
> (27,'2005-01-13 00:00:00',3),(28,'2005-01-14 00:00:00',4),
> (29,'2005-01-15 00:00:00',3),(30,'2005-01-16 00:00:00',0),
> (31,'2005-01-17 00:00:00',3),(32,'2005-01-18 00:00:00',4),
> (33,'2005-01-19 00:00:00',3),(34,'2005-01-20 00:00:00',2),
> (35,'2005-01-21 00:00:00',3),(36,'2005-01-22 00:00:00',4),
> (37,'2005-01-23 00:00:00',3),(38,'2005-01-24 00:00:00',1),
> (39,'2005-01-25 00:00:00',3),(40,'2005-01-26 00:00:00',4),
> (41,'2005-01-27 00:00:00',3),(42,'2005-01-28 00:00:00',2),
> (43,'2005-01-29 00:00:00',3),(44,'2005-01-30 00:00:00',4),
> (45,'2005-01-31 00:00:00',3),(46,'2004-12-31 00:00:00',0),
> (47,'2005-07-07 12:12:59',0),(48,'2005-07-07 12:21:33',0),
> (49,'2005-07-07 12:24:42',0),(50,'2005-07-07 12:26:20',0),
> (51,'2005-07-07 12:27:34',0),(52,'2005-07-07 12:28:21',0),
> (53,'2005-07-07 12:29:00',0),(54,'2005-07-07 14:05:09',0),
> (55,'2005-07-07 14:20:02',0),(56,'2005-07-07 14:20:33',0),
> (57,'2005-07-07 14:22:03',0),(58,'2005-07-07 14:22:09',0),
> (59,'2005-07-07 14:22:21',0),(60,'2005-07-07 14:22:28',0),
> (61,'2005-07-07 14:25:24',0),(62,'2005-07-07 14:25:42',0),
> (63,'2005-07-07 16:42:52',0),(64,'2005-07-07 16:43:09',0),
> (65,'2005-07-07 16:43:26',0),(66,'2005-07-07 16:43:34',0),
> (67,'2005-07-07 16:43:51',0),(68,'2005-07-07 16:44:59',0),
> (69,'2005-07-07 16:47:25',0),(70,'2005-07-07 16:48:26',0),
> (71,'2005-07-07 16:51:10',0),(72,'2005-07-07 16:52:37',0),
> (73,'2005-07-07 16:57:39',0),(74,'2005-07-07 16:58:47',0),
> (75,'2005-07-07 17:00:43',0),(76,'2005-07-07 17:00:53',0),
> (77,'2005-07-07 17:12:07',0),(78,'2005-07-07 17:53:46',0),
> (79,'2005-07-07 18:03:20',0),(80,'2005-07-07 18:05:19',0),
> (81,'2005-07-08 00:13:26',0),(82,'2005-07-08 01:05:06',0),
> (83,'2005-07-08 01:06:14',0),(84,'2005-07-08 01:06:32',0),
> (85,'2005-07-08 01:09:36',0),(86,'2005-07-08 01:11:51',0),
> (87,'2005-07-08 01:12:11',0),(88,'2005-07-08 01:12:19',0),
> (89,'2005-07-08 09:54:34',0),(90,'2005-07-08 09:59:11',0),
> (91,'2005-07-08 09:59:55',0),(92,'2005-07-08 10:26:02',0),
> (93,'2005-07-08 10:28:11',0),(94,'2005-07-08 10:28:25',0),
> (95,'2005-07-08 10:35:19',0),(96,'2005-07-08 10:36:16',0),
> (97,'2005-07-08 10:36:37',0),(98,'2005-07-08 10:38:07',0),
> (99,'2005-07-08 10:38:59',0),(100,'2005-07-08 10:39:24',0),
> (101,'2005-07-08 10:40:34',0),(102,'2005-07-08 10:42:24',0),
> (103,'2005-07-08 10:42:51',0),(104,'2005-07-08 10:43:37',0),
> (105,'2005-07-08 10:43:50',0),(106,'2005-07-08 10:44:08',0),
> (107,'2005-07-08 11:45:37',0),(108,'2005-07-08 11:45:44',0),
> (109,'2005-07-08 11:55:15',0),(110,'2005-07-08 11:57:01',0),
> (111,'2005-07-08 11:57:17',0),(112,'2005-07-08 11:57:27',0),
> (113,'2005-07-08 11:57:34',0),(114,'2005-07-08 11:57:43',0),
> (115,'2005-07-08 11:58:03',0),(116,'2005-07-08 11:58:36',0),
> (117,'2005-07-08 11:59:57',0),(118,'2005-07-08 12:00:24',0),
> (119,'2005-07-08 12:10:28',0),(120,'2005-07-08 13:56:29',0),
> (121,'2005-07-08 13:56:35',0),(122,'2005-07-08 13:56:43',0),
> (123,'2005-07-08 13:56:47',0),(124,'2005-07-08 13:57:13',0),
> (125,'2005-07-08 13:57:54',0),(126,'2005-07-08 13:58:35',0),
> (127,'2005-07-09 12:25:41',0),(128,'2005-07-09 12:26:42',0),
> (129,'2005-07-09 12:34:01',0),(130,'2005-07-09 12:35:11',0),
> (131,'2005-07-09 12:38:37',0),(132,'2005-07-09 12:46:47',0),
> (133,'2005-07-09 12:48:15',0),(134,'2005-07-09 12:49:48',0),
> (135,'2005-07-09 12:57:10',0),(136,'2005-07-09 13:17:12',0),
> (137,'2005-07-09 14:22:30',0),(138,'2005-07-09 14:23:11',0),
> (139,'2005-07-09 14:23:41',0),(140,'2005-07-09 19:11:40',0),
> (141,'2005-07-09 19:16:17',0),(142,'2005-07-09 19:17:45',0),
> (143,'2005-07-09 19:19:12',0),(144,'2005-07-10 01:06:42',0),
> (145,'2005-07-10 01:07:19',0),(146,'2005-07-10 01:07:39',0),
> (147,'2005-07-10 01:10:06',0),(148,'2005-07-10 02:00:46',0),
> (149,'2005-07-10 02:06:58',0),(150,'2005-07-10 02:08:19',0),
> (151,'2005-07-10 02:08:41',0),(152,'2005-07-10 02:09:50',0),
> (153,'2005-07-10 02:43:35',0),(154,'2005-07-12 10:20:00',0),
> (155,'2005-07-12 10:20:41',0),(156,'2005-07-12 10:21:01',0),
> (157,'2005-07-12 10:21:31',0);
>
>
>
> --
> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
> - -
> - Jason Pyeron PD Inc. http://www.pdinc.us -
> - Partner & Sr. Manager 7 West 24th Street #100 -
> - +1 (443) 921-0381 Baltimore, Maryland 21218 -
> - -
> -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
>
> This message is for the designated recipient only and may contain
> privileged, proprietary, or otherwise private information. If you
> have received it in error, purge the message from your system and
> notify the sender immediately. Any other use of the email by you
> is prohibited.
>
I believe you are beginning to feel the pain of a geometrically increasing
query load to execute this query. If I understand the intent of your
query, you want the most recently dated entry, in the same group as but
dated earlier than a given entry.
I would not try to do this query with a self join. Your execution time
approaches N! which gets horrible very quickly. A more linear approach is
to do this in two steps. This is similar to the group-wize maximum problem
detailed here:
http://dev.mysql.com/doc/mysql/en/example-maximum-column-group-row.html.
In your case, you want to find the row with the max() date for the subset
you specify (same group as but earlier date than your target record). (I
will generalize this to return the 5 most recent records not just the one
most recent)
SELECT @targetLevel := level from bvolset where id=30;
CREATE TEMPORARY TABLE tmpList
SELECT DISTINCT bdate
FROM bvolset
WHERE id<30
AND level =@targetLevel
ORDER BY bdate desc
Limit 5;
/* assuming, worst case, one entry per date then we will need at most 5
dates to find 5 records */
SELECT b.id, b.bdate, b.level
FROM bvolset b
INNER JOIN tmpList t
on t.bdate = b.bdate
ORDER BY b.bdate desc, b.id desc
LIMIT 5;
DROP TEMPORARY TABLE tmpList;
Most people are "afraid" of using multiple statement to do what can be
represented in a single query (like yours) but the performance advantages
can be enormous. Most of the slow queries that use self-joins or
subqueries will improve their performance remarkably by breaking them into
separate steps, like my example. Sure it takes more than one statement,
but it still works faster when performed correctly.
Shawn Green
Database Administrator
Unimin Corporation - Spruce Pine