My query is not using any indexes. Query performing full table scan. What can I do to avoid this?
explain select * from
timed_delivery_messages
where start_time <= '06:39'
and end_time > '06:39'
and mode='Active'
and rotation_weight like '%,45,%'
and substr(day_of_week, 2, 1) = 'T'
limit 1;
Explain Plan
+----+-------------+-------------------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------------------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | timed_delivery_messages | ALL | NULL | NULL | NULL | NULL | 22 | Using where |
+----+-------------+-------------------------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
Tables:
mysql> show create table timed_delivery_messages\G
*************************** 1. row ***************************
Table: timed_delivery_messages
Create Table: CREATE TABLE `timed_delivery_messages` (
`row_create` datetime DEFAULT NULL,
`row_mod` datetime DEFAULT NULL,
`rule_id` int(11) NOT NULL,
`start_time` time DEFAULT NULL,
`end_time` time DEFAULT NULL,
`day_of_week` varchar(7) DEFAULT NULL,
`rotation_weight` varchar(50) DEFAULT NULL,
`mode` varchar(10) DEFAULT 'active',
`long_message` varchar(256) DEFAULT NULL,
`short_message` varchar(256) DEFAULT NULL,
PRIMARY KEY (`rule_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
You must create one group index with columns
start_time,
end_time,
mode
And also do experiment to include day_of_week into this index. Maybe it will speed up your system
Related
I have a query like
SELECT `table1`.*
FROM `table1`
WHERE `table1`.`table2_id` IN (1,2,6,12,53,666)
and it works more than 20 seconds
Explain looks like:
+----+-------------+--------------------------+------------+-------+-------------------------------------------------------------------------------+----------------------------------+---------+------+-------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------------------------+------------+-------+-------------------------------------------------------------------------------+----------------------------------+---------+------+-------+----------+-----------------------+
| 1 | SIMPLE | table1 | NULL | range | table2_id | table2_id | 4 | NULL | 74778 | 100.00 | Using index condition |
+----+-------------+--------------------------+------------+-------+-------------------------------------------------------------------------------+----------------------------------+---------+------+-------+----------+-----------------------+
Table looks like
CREATE TABLE `table1` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`table2_id` int(11) NOT NULL,
`table3_id` int(11) NOT NULL,
`field1` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`field2` int(11) NOT NULL DEFAULT '0',
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
`field3` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `name_of_index_id` (`table3_id`),
KEY `other_name_of_index` (`field2`),
KEY `table2_id` (`table2_id`)
) ENGINE=InnoDB AUTO_INCREMENT=86623178 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
You can use index to fetch the result quickly. But, Indexing will take more space to generate and store in the database. So, if you are fine to utilize speed compare to space, Indexing will be used with following SQL statement.
ALTER TABLE `table1` ADD INDEX(`table2_id`);
Please refer the table strcuture below.
CREATE TABLE `oarc` (
`ID` bigint(20) NOT NULL AUTO_INCREMENT,
`zID` int(11) NOT NULL,
`cID` int(11) NOT NULL,
`bID` int(11) NOT NULL,
`rtype` char(1) COLLATE utf8_unicode_ci NOT NULL,
`created` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1821039 ;
Other than the PRIMARY KEY, I have not set any index on this, and when I run the following query
select COUNT(oarc.ID) as total
from `oarc` where`oarc`.`rtype` = 'v'
group
by `oarc`.`zID`
I am getting the result in less than 1 second. But if I add index to zID it is taking more than 5 seconds.
Please see below explain result :
id | select_type | table | type | possible_keys | key | key_len | ref | row | Extra
--------------------------------------------------------------------------------------------------------
1 | SIMPLE | oarc | index | NULL | zone_ID | 4 | NULL | 1909387 | Using where
Currently the table have more than 1821039 records in it and it will increase on a hourly basis. What are the things I need to do in order to reduce the query execution time. I am expecting only something at the table and query level, nothing on my.cnf or server side because I can not do anything there.
Thanks in advance.
Is this better?
CREATE TABLE `oarc` (
`ID` bigint(20) NOT NULL AUTO_INCREMENT,
`zID` int(11) NOT NULL,
`cID` int(11) NOT NULL,
`bID` int(11) NOT NULL,
`rtype` char(1) COLLATE utf8_unicode_ci NOT NULL,
`created` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`ID`),
KEY(rtype,zid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1821039 ;
explain
select COUNT(oarc.ID) as total
from `oarc` where`oarc`.`rtype` = 'v'
group
by `oarc`.`zID`
+----+-------------+-------+------+---------------+-------+---------+-------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+-------+---------+-------+------+--------------------------+
| 1 | SIMPLE | oarc | ref | rtype | rtype | 3 | const | 1 | Using where; Using index |
+----+-------------+-------+------+---------------+-------+---------+-------+------+--------------------------+
I am kind of new to this whole INDEXING thing, but am loving it so far! Just a quick (possibly very easy) question...I have a very basic query, where I want to select just the 5 most recent comments from the "comments" table. The "id" column is the PRIMARY.
mysql> EXPLAIN SELECT * FROM comments ORDER BY id DESC LIMIT 5;
+----+-------------+----------+-------+---------------+---------+---------+------+-------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+-------+---------------+---------+---------+------+-------+-------+
| 1 | SIMPLE | comments | index | NULL | PRIMARY | 4 | NULL | 19938 | |
+----+-------------+----------+-------+---------------+---------+---------+------+-------+-------+
1 row in set (0.00 sec)
As you can see, it is scanning the entire table...is there any way around this?
UPDATE for SHOW CREATE TABLE comments:
mysql> show create table comments;
+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| comments | CREATE TABLE `comments` (
`id` int(12) NOT NULL auto_increment,
`post_id` int(12) NOT NULL,
`comm_id` int(11) NOT NULL,
`userid` int(12) NOT NULL,
`name` varchar(30) NOT NULL,
`content` text NOT NULL,
`location` varchar(30) NOT NULL,
`type` enum('Comment','Advice') NOT NULL,
`likes` int(12) NOT NULL,
`dislikes` int(12) NOT NULL,
`datetime` varchar(255) NOT NULL,
`datetimerss` varchar(255) NOT NULL,
`ip` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `type` (`type`)
) ENGINE=MyISAM AUTO_INCREMENT=20091 DEFAULT CHARSET=latin1 |
+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
I have a table
CREATE TABLE tb_incident (
id int(10) unsigned NOT NULL AUTO_INCREMENT,
what tinyint(4) NOT NULL,
when bigint(20) unsigned NOT NULL,
where tinytext NOT NULL,
where_longitude_latitude point NOT NULL,
who tinyint(4) DEFAULT NULL,
why tinyint(4) DEFAULT NULL,
description text,
created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY id_UNIQUE (id),
KEY index_main_items (what,when),
SPATIAL KEY location_index (where_longitude_latitude)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
When I try running this query,
SELECT db_incident.distance(point(132.6,15.604436765987833),where_longitude_latitude,'mi') AS "Distance in miles",
X(where_longitude_latitude) AS "Longitude",
Y(where_longitude_latitude) AS "Latitude"
FROM db_incident.tb_incident
WHERE db_incident.distance(point(132.6,15.604436765987833),where_longitude_latitude,'mi') <= 5
LIMIT 100
It takes over 10 minutes to execute, sometimes it gives this error Error Code: 2013. Lost connection to MySQL server during query
My table has over 10 million records. Can someone please take a look and see if there is a way the query can be optimized.
NOTE: db_incident.distance is a function that returns the distance between two points.
Below is the EXPLAIN of the query.
+----+-------------+-------------+------+---------------+------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------+------+---------------+------+---------+------+----------+-------------+
| 1 | SIMPLE | tb_incident | ALL | NULL | NULL | NULL | NULL | 11689629 | Using where |
+----+-------------+-------------+------+---------------+------+---------+------+----------+-------------+
1 row in set (0.00 sec)
What's going on here? BTW, MySQL Server version: 5.0.45-log Source distribution.
mysql> select count(*)
from notes
where date(updated_at) > date('2010-03-25');
+----------+
| count(*) |
+----------+
| 0 |
+----------+
1 row in set (0.59 sec)
mysql> select count(*)
from notes
where message like'%***%'
and date(updated_at) > date('2010-03-25');
+----------+
| count(*) |
+----------+
| 26 |
+----------+
1 row in set (1.30 sec)
mysql> explain select count(*)
from notes
where date(updated_at) > date('2010-03-25');
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | notes | ALL | NULL | NULL | NULL | NULL | 588106 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
1 row in set (0.07 sec)
mysql> explain select updated_at
from notes
where message like'%***%'
and date(updated_at) > date('2010-03-25');
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | notes | ALL | NULL | NULL | NULL | NULL | 588106 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
1 row in set (0.09 sec)
mysql>
Here's the table schema.
CREATE TABLE `notes` (
`id` int(11) NOT NULL auto_increment,
`status` varchar(255) default NULL,
`message` text,
`noteable_id` int(11) default NULL,
`noteable_type` varchar(255) default NULL,
`deleted_at` datetime default NULL,
`creator_id` int(11) default NULL,
`updater_id` int(11) default NULL,
`deleter_id` int(11) default NULL,
`created_at` datetime default NULL,
`updated_at` datetime default NULL,
`public` tinyint(1) default '0',
`forced` tinyint(1) default '0',
`agent_created_at` datetime default NULL,
PRIMARY KEY (`id`),
KEY `noteable_id` (`noteable_id`),
KEY `deleted_at` (`deleted_at`),
KEY `noteable_type` (`noteable_type`(10)),
KEY `creator_id` (`creator_id`),
KEY `status` (`status`),
KEY `created_at` (`created_at`)
) ENGINE=InnoDB AUTO_INCREMENT=613168 DEFAULT CHARSET=latin1
If the table is small, try dumping & reloading on a fresh server on another box (with the same version). If the problem goes away, there is some internal corruption and you will need to either reload the table on the existing server, or reinit the entire database from a dump.
If the behaviour is reproducible on a clean database and nobody can explain it (after you post the schema etc), then raise a bug.
It turns out, this particular instance was not caused by database corruption, but a bug in the Date function for MySQL version 5.0.45 (+?).
http://bugs.mysql.com/bug.php?id=32159
We don't see a need to react to this situation immediately, but we will be migrating to a higher version of MySQL (either 5.0.77+ or 5.1)