Why EXPLAIN SQL result for KEY is NULL - mysql

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.

Related

Error on creating foreign key relationship between non-primary key

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.

Tuning SQL Query for a table with size more than 2GB

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...

Issues with creating a foreign key

I'm having issues with setting up a relation between 2 tables called Customer and Customer_Number. I have both tables set to InnoDB both have indexes, but when I go to create the foreign key, I get a "no index defined" error. Below are some screen shots
Here Is the Customer table.
Here is the Customer_Number table.
And here is my error message when trying to create the foreign key.
And lastly, this is the error I get when trying to create the relationship manually.
I just can't seem to figure out the issue, and it's driving me nuts!
the output for SHOW CREATE TABLE Customer is
CREATE TABLE `Customer` (
`Customer_ID` int(11) NOT NULL AUTO_INCREMENT,
`First` varchar(255) NOT NULL,
`Last` varchar(255) NOT NULL,
PRIMARY KEY (`Customer_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
and the output for SHOW CREATE TABLE Customer_Number is
CREATE TABLE `Customer_Number` (
`Num_ID` int(11) NOT NULL AUTO_INCREMENT,
`Customer_ID` int(11) NOT NULL,
`Number` varchar(255) NOT NULL,
PRIMARY KEY (`Num_ID`),
KEY `Customer_ID` (`Customer_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
The two CREATE TABLE statements as posted are correct and should be able to accept a new FOREIGN KEY constraint on Customer_Number.Customer_ID since the necessary criteria are met (same data type as referenced column, comparable index or primary key on referenced column).
An ALTER statement succeeds in my testing:
ALTER TABLE Customer_Number ADD FOREIGN KEY (Customer_ID) REFERENCES Customer (Customer_ID);
Being unfamiliar with how PhpMyAdmin abstracts some RDBMS errors, it is hard to say for sure what exactly has gone wrong in the GUI. But if you run the ALTER statement manually and encounter errors about failed foreign key constraints, that's an indication the referencing table already contains values in the column which do not reference a valid row value in the parent table. To uncover those rows so you can address them, execute a query like:
SELECT * FROM Customer_Number WHERE Customer_ID NOT IN (SELECT Customer_ID FROM Customer)
Once you have found the problematic rows, you can either delete them (if unneeded) or update their values to the value of a valid row value in the referenced table. If the column's definition allowed NULL (which yours does not) you could also UPDATE them to set them NULL then run the ALTER statement again.
It is also possible to disable foreign key checks temporarily, add the constraint, update the rows to match valid parent table values, the reenable foreign key checks.
please try this.
alter table Customer_Number add foreign key(customer_ID) references Customer (Customer_ID);

Struggling to create correct index for simple sorted range query

In my database, I have a table 'karmalog'. It basically is a log of actions in the system. It contains a few 100ks of rows. I'd like to retrieve the newest 36 of log items, but only those log items that match a series of log type (called 'event').
Here's the query:
SELECT id
FROM karmalog
WHERE event
IN (
'FAV_IMG_ADD', 'FOLLOW', 'COM_POST', 'IMG_VOTE', 'LIST_VOTE', 'JOIN', 'CLASS_UP', 'LIST_CREATE', 'FORUM_REPLY', 'FORUM_CREATE', 'FORUM_SUBSCRIBE', 'IMG_GEO', 'IMG_ADDSPECIE', 'SPECIE_ADDVIDEO', 'EARN_MEDAL'
)
ORDER BY id DESC
LIMIT 0 , 36
This query currently takes between 0.2 - 0.5s. I'd like to get it into the 0.00x range. As the above query retrieves a single column, a single condition, and a single sort parameter, I figured I'd just create a proper index and all will be good. No luck so far. Here's the table definition, stripped from irrelevant fields:
DROP TABLE IF EXISTS `karmalog`;
CREATE TABLE `karmalog` (
`id` int(11) NOT NULL auto_increment,
`event` enum('EDIT_PROFILE','EDIT_AVATAR','EDIT_EMAIL','EDIT_PASSWORD','FAV_IMG_ADD','FAV_IMG_ADDED','FAV_IMG_REMOVE','FAV_IMG_REMOVED','FOLLOW','FOLLOWED','UNFOLLOW','UNFOLLOWED','COM_POSTED','COM_POST','COM_VOTE','COM_VOTED','IMG_VOTED','IMG_UPLOAD','LIST_CREATE','LIST_DELETE','LIST_ADMINDELETE','LIST_VOTE','LIST_VOTED','IMG_UPD','IMG_RESTORE','IMG_UPD_LIC','IMG_UPD_MOD','IMG_UPD_MODERATED','IMG_VOTE','IMG_VOTED','TAG_FAV_ADD','CLASS_DOWN','CLASS_UP','IMG_DELETE','IMG_ADMINDELETE','IMG_ADMINDELETEFAV','SET_PASSWORD','IMG_RESTORED','IMG_VIEW','FORUM_CREATE','FORUM_DELETE','FORUM_ADMINDELETE','FORUM_REPLY','FORUM_DELETEREPLY','FORUM_ADMINDELETEREPLY','FORUM_SUBSCRIBE','FORUM_UNSUBSCRIBE','TAG_INFO_EDITED','JOIN','IMG_GEO','IMG_ADDSPECIE','IMG_REMOVESPECIE','SPECIE_ADDVIDEO','SPECIE_REMOVEVIDEO','EARN_MEDAL') NOT NULL,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `user_sec_id` (`user_sec_id`),
KEY `image_id` (`object_id`),
KEY `date_event` (`date_created`,`event`),
KEY `event` (`event`),
KEY `date_created` (`date_created`),
KEY `date_created_2` (`date_created`,`id`),
KEY `event_2` (`event`,`delete`),
CONSTRAINT `user_id` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE SET NULL,
CONSTRAINT `user_sec_id` FOREIGN KEY (`user_sec_id`) REFERENCES `user` (`id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
As you can see, I've tried a few indices already. Not shown in this version were two other index attempts (id, event and event, id), both to no avail. In all combinations tried so far, MySQL explain keeps saying it is using filesort.
Any ideas?
This is your query:
SELECT id
FROM karmalog
WHERE event IN ('FAV_IMG_ADD', 'FOLLOW', 'COM_POST', 'IMG_VOTE', 'LIST_VOTE', 'JOIN',
'CLASS_UP', 'LIST_CREATE', 'FORUM_REPLY', 'FORUM_CREATE', 'FORUM_SUBSCRIBE',
'IMG_GEO', 'IMG_ADDSPECIE', 'SPECIE_ADDVIDEO', 'EARN_MEDAL'
)
ORDER BY id DESC
LIMIT 0 , 36;
The first index to try is karmalog(event, id). The second is karmalog(id, event). Neither of these are in your list.

MySQL not using multiple column index

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