When i have both primary key columns and non primary key columns in select clause, EXPLAIN output under Extra shows empty as below:
Query :
EXPLAIN SELECT aggEI.c_id AS companyId,aggEI.uid AS uuid,
aggEI.rating AS rating, aggEI.ei_name AS name
FROM AGG_EI AS aggEI
where aggEI.c_id in (8)
1 SIMPLE aggEI ref agg_ei_comdm_fk_idx agg_ei_comdm_fk_idx 8 const 65909
In the above query c_id,uid columns are part of primary key and rating,name are not part of primary key.
If i remove non primary keys from the select clause query is using index as below:
EXPLAIN SELECT aggEI.c_id AS companyId,
aggEI.c_id AS uuid
FROM AGG_EXTERNALINDIVIDUAL AS aggEI
where aggEI.c_id in (8)
1 SIMPLE aggEI ref agg_ei_comdm_fk_idx agg_ei_comdm_fk_idx 8 const 65909 Using index
Where agg_ei_comdm_fk_idx is the foreign key index on column c_id .
Can someone explain me this behaviour. What combination of index do i need to have to make query use index
Create Table:
CREATE TABLE IF NOT EXISTS `AGG_EI` (
`c_id` BIGINT NOT NULL ,
`uid` VARCHAR(150) NOT NULL ,
`ei_name` VARCHAR(150) NOT NULL ,
`rating` DOUBLE NULL ,
`cnt` DOUBLE NULL ,
PRIMARY KEY ( `c_id`, `uid`) ,
INDEX `agg_ei_comdm_fk_idx` (`c_id` ASC) ,
UNIQUE INDEX `id_UNIQUE` ( `c_id` ASC, `uid` ASC) ,
CONSTRAINT `agg_ei_comdm_fk`
FOREIGN KEY (`c_id` )
REFERENCES `COMPDM` (`c_id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION
ENGINE = InnoDB;
For unique indexes (including PK) the explain doesn't show in Extra column 'Using index' but that does mean its not using it ... in fact to be sure that a index is use you need to check the key column which specifies what index is use , if this is blank then indeed no index is used.
You can see the result in this fiddle.
Related
Hi all I have this table schema
create table user_activities
(
id int unsigned auto_increment
primary key,
user_id int unsigned not null,
other_user_id int unsigned not null,
activity_type_id tinyint unsigned not null,
reason varchar(255) null,
created_at timestamp default CURRENT_TIMESTAMP not null,
updated_at timestamp default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP,
constraint user_activities_user_id_other_user_id_unique
unique (user_id, other_user_id),
constraint user_activities_other_user_id_foreign
foreign key (other_user_id) references users (id),
constraint user_activities_activity_type_id_foreign
foreign key (activity_type_id) references user_activity_types (id),
constraint user_activities_user_id_foreign
foreign key (user_id) references users (id)
)
engine = InnoDB
collate = utf8_unicode_ci;
create index user_activities_other_user_id_index
on user_activities (other_user_id);
create index user_activities_activity_type_id_index
on user_activities (activity_type_id);
create index user_activities_user_id_index
on user_activities (user_id);
The table has now 6515846 rows
Goal
I want to write a query to get the users that had the most recent activity in the last 7 days.
I need rows of user_id, mostrecentuseractivitydate
Then in the code I will do some action on them.
My query at the moment is
select updated_at, user_id from user_activities
where created_at > '2022-08-08 15:16:55'
group by user_id
order by max(updated_at) desc
limit 10;
The explain statement result is
1,SIMPLE,user_activities,,index,"user_activities_user_id_other_user_id_unique,user_activities_user_id_index",user_activities_user_id_index,4,,6416255,33.33,Using where; Using temporary; Using filesort
Problem
The query above with the given schema and number of rows takes forever like 5 minutes... and sometimes I receive no response and query hangs forever
That is not acceptable for my requirement.
Any ideas how to speed that up ?
I have already foreign_key as you can see from table schema on the user_id field and the innodb I think also generates index automatically on the foreign key.
I am also adding the where created_at > clause to reduce only the the items in the 7 days.
I even tried without adding the where created_at and did not change much to be honest.
Anyway I am interested only in the data from last 7 days so that where clause can stay
You need an index on created_at. Others might be useful as well, but start there.
You want to have a composite key with user_id and created_at in it.
This key should make it possible to do the group by as well as the where clause at the same time.
Try this:
create index user_activities_user_id_created_at on user_activities (user_id, created_at);
I have created INDEX for my table but when use explain QUERY the result for key is NULL.
my table as below:
TABLE list_country
id
id_tx
id_ref_country FK TO id in ref_country
cost
cceiling
INDEX FOR list_country:
id PRIMARY
id_tx,id_ref_country UNIQUE
id_tx KEY
id_ref_country KEY
TABLE ref_country
id
country_name
INDEX for ref_country:
id PRIMARY
i run explain query as below:
EXPLAIN
SELECT ctr.id_tx
, GROUP_CONCAT(rctr.country_name,':',cost) AS cost_country
, GROUP_CONCAT(rctr.country_name,':',cceiling) AS ceiling_country
, GROUP_CONCAT(rctr.country_name) AS country
FROM list_country ctr
LEFT JOIN ref_country rctr ON rctr.id = ctr.id_ref_country
GROUP BY id_tx
RESULT EXPLAIN FOR TABLE list_country TYPE = ALL, KEY = NULL
Why the key is null for list_country even i specify the index?
The DDL for this table:
CREATE TABLE `list_country` (
`id` INT NOT NULL AUTO_INCREMENT,
`id_tx` INT NOT NULL,
`id_ref_country` INT NOT NULL,
`cost` DECIMAL(15,2) DEFAULT NULL,
`cceiling` DECIMAL(15,2) DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `country_unik` (`id_tx`,`id_ref_country`) USING BTREE,
KEY `id_tx` (`id_tx`) USING BTREE,
KEY `id_ref_country` (`id_ref_country`) USING BTREE,
CONSTRAINT `list_country_ibfk_1` FOREIGN KEY (`id_tx`) REFERENCES `ep_tx` (`id_tx`) ON DELETE RESTRICT ON UPDATE RESTRICT,
CONSTRAINT `list_country_ibfk_2` FOREIGN KEY (`id_ref_country`) REFERENCES `ref_country` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=INNODB AUTO_INCREMENT=55609 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
To get the results for you query, MySSQL needs to get the info of the following fields:
ctr.id_tx
ctr.id_ref_country
Because of this, only the index country_unik can be used, it contains both fields, or MySQL can just read the complete table.
EXPLAIN Output Format says, about Type=ALL:
A full table scan is done for each combination of rows from the
previous tables. This is normally not good if the table is the first
table not marked const, and usually very bad in all other cases.
Normally, you can avoid ALL by adding indexes that enable row
retrieval from the table based on constant values or column values
from earlier tables.
MySQL is avoiding the use of the index, because it needs all records for that table.
I have a table called requests on which the columns are id, placeId, songId, userId
id is the primary index of the table. Rest of the columns are only unsigned integers and no other unique key is defined.
I want placeId & songId pairs to be unique, i.e., if a row has placeId : 5 and songId : 12, no other rows can have the same combination.
I want this check to happen in SQL level, so that I can query like insert into requests (...) values (...) on duplicate key do something else
you can create a UNIQUE index on multiple columns like this
CREATE UNIQUE INDEX placeSong
ON requests (placeId, songId)
Another method is to add an unique constraint to the table :
ALTER TABLE requests ADD CONSTRAINT placeSong UNIQUE( placeId , songId );
CREATE TABLE `tbl` (
`ID` INT(11) NOT NULL AUTO_INCREMENT,
`field1` VARCHAR(45) NOT NULL DEFAULT '',
`field2` VARCHAR(20) NOT NULL DEFAULT '',
PRIMARY KEY (`ID`),
UNIQUE INDEX `Index 2` (`field1`, `field2`)
);
I have query with columns in where clause which are part of primary key and have foreign key indexes on all columns.
EXPLAIN SELECT aggEI.c_id AS companyId, aggEI.ei_uid AS uuid
FROM AGG_EI AS aggEI
WHERE aggEI.c_id in (8) and aggEI.tg_id IN (1,2,3,4,5,6,7)
AND aggEI.dt_id = 20130506
I have also defined multiple columnn index on (c_id,tg_id,dt_id) but EXPLAIN shows that it is using foreign key index on c_id
1 SIMPLE aggEI ref PRIMARY,datedm_id_UNIQUE,agg_ei_comdm_fk_idx,agg_ei_datedm_fk_idx,agg_ei_topgrp_fk_idx,comp_uuid agg_ei_comdm_fk_idx 8 const 65986 Using where; Using index
agg_ei_comdm_fk_idx is the foreign key index on c_id and comp_uuid is the multiple column index on (c_id,tg_id,dt_id)
Can someone explain why it is happening like this
EDIT: Create table
'CREATE TABLE `AGG_EI` (
`dt_id` int(11) NOT NULL,
`c_id` bigint(20) NOT NULL,
`tg_id` bigint(20) NOT NULL,
`ei_uid` varchar(150) NOT NULL
`ei_name` varchar(150) NOT NULL,
`rating` double NOT NULL,
`cnt` double NOT NULL
PRIMARY KEY (`dt_id`,`c_id`,`tg_id`,`ei_uid`),
UNIQUE KEY `datedm_id_UNIQUE` (`dt_id`,`c_id`,`ei_uid`,`tg_id`),
KEY `agg_ei_comdm_fk_idx` (`c_id`),
KEY `agg_ei_datedm_fk_idx` (`dt_id`),
KEY `agg_ei_topgrp_fk_idx` (`tg_id`),
KEY `comp_uuid` (`c_id`,`tg_id`,`dt_id`),
CONSTRAINT `agg_ei_comdm_fk` FOREIGN KEY (`c_id`) REFERENCES `COMPDM` (`c_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `agg_ei_datedm_fk` FOREIGN KEY (`dt_id`) REFERENCES `DATEDM` (`dt_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `agg_ei_topgrp_fk` FOREIGN KEY (`tg_id`) REFERENCES `TOPGRP` (`tg_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8'
MySQL is performing the query using the plan that it thinks will perform the best. More than likely, it determined that limiting c_id to a single value reduced the result set to few enough rows that going to the trouble of dealing with the extra columns in the other index wasn't worth it. MySQL's best guess is that it's faster to limit the rows using just c_id and then just filter those rows in memory. Just because you have an index doesn't mean that's the fastest plan.
You can force mysql to use a index like :
EXPLAIN
SELECT
aggEI.c_id AS companyId,
aggEI.ei_uid AS uuid
FROM
AGG_EI AS aggEI FORCE INDEX(`comp_uuid`)
WHERE
aggEI.c_id in (8)
AND aggEI.tg_id IN (1,2,3,4,5,6,7)
AND aggEI.dt_id = 20130506
When I use MySQL Workbench to create a simple table with a single primary key, it not only creates the PK index (cool) but also a second Unique Index (?). Here's an example output:
CREATE TABLE `tbl_example` (
`tbl_example_ID` INT(10) UNSIGNED NOT NULL ,
`field1` VARCHAR(45) NULL ,
`field2` VARCHAR(45) NULL ,
PRIMARY KEY (`tbl_example_ID`) ,
UNIQUE INDEX `tbl_example_ID_UNIQUE` (`tbl_example_ID` ASC) )
ENGINE = MyISAM
It's my understanding that a PK assumes unique index so the UNIQUE INDEX line is unnecessary, correct? Just looking for some confirmation before I update a bunch of tables.
You are right. A Primary Key is (for MySQL) a unique index with the name 'PRIMARY KEY'. So having a Primary Key and a unique index on the same column(s) is a pointless waste of resources.