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
Related
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 two table
CREATE TABLE `abc` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ref_id` varchar(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ref_id_UNIQUE` (`ref_id`)
)
CREATE TABLE `xyz` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ref_id` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ref_id_UNIQUE` (`ref_id`)
)
I want to make foreign key relation ship between xyz's ref_id and abc's ref_id .But Mysql gives error 1215.
You should make the foreign key relationships to the primary keys. I know that MySQL allows foreign key relationships to anything with an index. But the correct practice is to use primary keys.
So declare the table like this:
CREATE TABLE `xyz` (
`id` int(11) NOT NULL AUTO_INCREMENT,
abc_id int DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ref_id_UNIQUE` (`abc_id`),
ADD CONSTRAINT fk_xyz_abc FOREIGN KEY (abc_id) REFERENCES abc(id)
);
If you want the ref_id for an xyz row, then use JOIN to get the information.
Take a look at Gordon Linoff's answer, his suggestion makes sense, even though it does not answer the question. So what can cause an error when you intend to create a foreign key relationship? The obvious possibility is syntax error and typo, so you will need to check against those and fix any such problems.
Another possibility is that you have inconsistency, that is, you try to create a foreign key constraint in one of your tables, but not all the values have exact matches. So, assuming that you have Foo and Bar table and you intend Foo.lorem to be a foreign key referencing Bar.ipsum, then you will need to ensure that all the values you have for Foo.lorem has a Bar.ipsum pair with the exact same values (except null). If that's not true, then your foreign key constraint will not be successfully created. Find such inconsistencies:
select distinct Foo.lorem
from Foo
where not (Foo.lorem is null) and
not exists (select 1 from Bar where Foo.lorem = Bar.ipsum);
Read the lines carefully and make sure you fix any such Foo.lorem values.
I have a table with millions of records and the size of table currently is 2GB and expected to grow further
Table Structure
CREATE TABLE `test` (
`column_1` int(11) NOT NULL AUTO_INCREMENT,
`column_2` int(11) NOT NULL,
`column_3` int(11) NOT NULL,
`column_4` int(11) NOT NULL,
`column_5` datetime NOT NULL,
`column_6` time NOT NULL,
PRIMARY KEY (`column_1`),
UNIQUE KEY `index_1` (`column_2`,`column_3`),
UNIQUE KEY `index_2` (`column_2`,`column_4`),
KEY `index_3` (`column_3`),
KEY `index_4` (`column_4`),
KEY `index_5` (`column_2`),
KEY `index_6` (`column_5`,`column_2`),
CONSTRAINT `fk_1` FOREIGN KEY (`column_3`) REFERENCES `test2`(`id`),
CONSTRAINT `fk_2` FOREIGN KEY (`column_4`) REFERENCES `test2` (`id`),
CONSTRAINT `fl_3` FOREIGN KEY (`column_2`) REFERENCES `link` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=14164023 DEFAULT CHARSET=utf8;
When I run the following query it is taking around 5-8 secs for different values of column_2. Can some one help to execute this better ?
SELECT count(*) FROM test WHERE test.column_2= 26 and
test.column_5 between '2015-06-01 00:00:00' AND
'2015-06-30 00:00:00' ;
Note: The timings mentioned are captured by executing the query on mysql work bench
Your index_6 currently has column_5, then column_2, so MySQL first tries to filter based on the BETWEEN clause. However MySQL has limitation that after using index in range mode, it can't use the 2nd part of the index (more info in this blog post).
The correct way of optimizing such queries is to have the equation column as 1st part of index and the range column as second. Then MySQL will choose rows which have column_2 value of 26 and then will use 2nd part of index to further filter them based on column_5 date range.
So the solution is to have an index:
KEY `ind_c2_c5` (`column_2`,`column_5`)
BTW it is better to give indexes descriptive names, so you know on first sight what they are for...
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.
How to use indexes with more than one column
The original index has an index on block_id, but is it necesarry when it's already in the unique index with two column?
Indexes with more than one column
(a,b,c)
you can search for a, b and c
you can search for a and b
you can search for a
you can not search for a and c
Does this apply to unique indexes too?
table
id
block_id
account_id
name
indexes origin
PRIMARY KEY (`id`)
UNIQUE KEY `block_id` (`block_id`,`account_id`)
KEY `block_id` (`block_id`),
KEY `account_id` (`account_id`),
indexes alternative
PRIMARY KEY (`id`)
UNIQUE KEY `block_id` (`block_id`,`account_id`)
KEY `account_id` (`account_id`),
The rules you describe above have to my knowledge always held whether an index is unique or not. You might run explain on the query you have in mind and observe when the index is used and when it is not used under various circumstances.