mysql and indexes with more than one column - mysql

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.

Related

Why EXPLAIN SQL result for KEY is NULL

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.

MySQL. UNIQUE and PRIMARY KEY constraints for the same field

I found some legacy code, which sets two almost identical constraints (UNIQUE and PRIMARY KEY) for the primary key field.
Here is the code sample:
CREATE TABLE foofoo (
id NUMERIC(9) NOT NULL ,
bar VARCHAR(40) NOT NULL,
CONSTRAINT PK_foofoo PRIMARY KEY (id),
CONSTRAINT UNIQUE_foofoo UNIQUE(id)
)
I think it's redundant to have these two set and PRIMARY KEY would do the job.
Of course, I read what's the difference between these two constraints, but
what's the point of setting these two constraints for the same field?
There is no point in doing so. A primary key is always unique by nature. I would advise against making both indexes, as indexes comes with a cost (mainly disk space). Just create the PK and you'll be good!
There is no point on setting the exact same constraint as the PK.
A Primary Key is already making sure that this column is unique and indexed.
I think it's redundant ...
Yes indeed it's redundant; since having primary key constraint on the column anyways will make sure that the column has only unique value. There is no point in defining an extra UNIQUE constraint on the same column.
when you declare primary then:
*PRIMARY KEY constraint uniquely identifies each record in a database table
*Primary keys must contain UNIQUE values
so their is no need to declare primary key unique because whenever u declare anything primary key then UNIQUE value is already attached with them.
For unique key:
*The UNIQUE constraint uniquely identifies each record in a database table.
*The UNIQUE and PRIMARY KEY constraints both provide a guarantee for uniqueness for a column or set of columns.
*A PRIMARY KEY constraint automatically has a UNIQUE constraint defined on it.
The most important point is that
*Note that you can have many UNIQUE constraints per table, but only one PRIMARY KEY constraint per table.
In mysql when i take same as primary key and Unique then it gave me error

MySQL - indexing innodb foreign keys

Is there an improvement in performance in indexing foreign keys in InnoDB? As far as I have read, InnoDB automatically creates an index for the foreign key.
Here is the query given to me for creating the table.
DROP TABLE IF EXISTS `assignments`;
CREATE TABLE `assignments`
(
`id` INTEGER NOT NULL AUTO_INCREMENT,
`user` INTEGER NOT NULL,
`job` INTEGER NOT NULL,
`created_at` DATETIME,
`updated_at` DATETIME,
PRIMARY KEY (`id`),
INDEX `job_fk1` (`user`),
INDEX `job_fk2` (`job`),
CONSTRAINT `job_fk1`
FOREIGN KEY (`user`)
REFERENCES `users` (`id`),
CONSTRAINT `job_fk2`
FOREIGN KEY (`job`)
REFERENCES `jobs` (`id`)
) ENGINE=InnoDB;
In there, he created foreign keys named job_fk1 and job_fk2. He used the names of these foreign keys as the name of the index.
Is there an improvement in performance in indexing foreign keys in InnoDB?
Answer: No. Performance will be degraded due to duplicate keys.
You do not need
INDEX `job_fk1` (`user`),
INDEX `job_fk2` (`job`),
Those will be automatically created by InnoDB internally. But you need to have index on users (id) and jobs (id) for faster operations on assignments table
http://dev.mysql.com/doc/refman/5.0/en/innodb-foreign-key-constraints.html
"InnoDB requires indexes on foreign keys and referenced keys so that foreign key checks can be fast and not require a table scan. In the referencing table, there must be an index where the foreign key columns are listed as the first columns in the same order. Such an index is created on the referencing table automatically if it does not exist. (This is in contrast to some older versions, in which indexes had to be created explicitly or the creation of foreign key constraints would fail.) index_name, if given, is used as described previously."
You are correct that MySQL will create an index on a column, if it doesn't already exist, when creating a foreign key constraint. However, feel free to create an index on the column and remove the auto-generated one if you want.
You also might want additional multi-column indexes to aid queries like this make-believe one:
SELECT id, user, job
FROM assignments
WHERE job = 5
ORDER BY user
The multi-column index (job, user) would satisfy both the search and the sort, and since secondary indexes include the primary key, it would also act as a covering index in this case.

MySQL INSERT INTO tables with foreign key speed is very slow

I'm trying to insert (from postgres via grails) about 10 millions records into a table with a primary key and 2 foreign keys. If I keep the all primary and foreign keys and the indexes automatically generated along with these keys, it'll take about 7.5 hours to complete. If I drop all the keys and indexes before the inserts, it'll take only 10 minutes to executes all the inserts. But when I used ALTER TABLE to add the keys back in, it took forever (more than 7 hours) to perform. Is there a way to improve the performance?
The concept table that this table linked to has about 1 million records.
Here's the CREATE TABLE statement:
CREATE TABLE `concept_relationship` (
`concept_id_1` int(11) NOT NULL,
`concept_id_2` int(11) NOT NULL,
`relationship_id` int(11) NOT NULL,
`valid_start_date` date NOT NULL,
`valid_end_date` date NOT NULL DEFAULT '2099-12-31',
`invalid_reason` char(1) DEFAULT NULL,
PRIMARY KEY (`concept_id_1`,`concept_id_2`,`relationship_id`),
KEY `concept_id_1` (`concept_id_1`),
KEY `concept_id_2` (`concept_id_2`),
KEY `relationship_id` (`relationship_id`),
CONSTRAINT `FK_CONCEPT_REL_child` FOREIGN KEY (`concept_id_2`) REFERENCES `concept` (`concept_id`),
CONSTRAINT `FK_CONCEPT_REL_Parent` FOREIGN KEY (`concept_id_1`) REFERENCES `concept` (`concept_id`),
CONSTRAINT `FK_CONCEPT_REL_REL_TYPE` FOREIGN KEY (`relationship_id`) REFERENCES `relationship` (`relationship_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Thanks for your help
First, the index concept_id_1 is not needed. The primary key covers this index entirely.
My suggestion is to create the table without the keys or foreign references, except for the primary key. When you insert into the table, be sure that the input data is sorted by the keys of the primary key. Then add back the other keys with explicit index creation:
create index concept_relationship_idx1 on concept_relationship(concept_id_1);
And so on.
If this doesn't work efficiently, then reconsider the primary key. The data is actually ordered by the primary key, which can be computationally intensive for inserts. Add an auto-incremented primary key. Insert the data. Then create a unique index for what is now the primary key, and indexes for the other keys.

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