MySQL indexes with multiple field - mysql

Would the following table considered to have duplicate indexes on TypeId, or is it perfectly fine to do it this way? Some of my queries perform faster using the KEY "covered', while others perform better just using the 'TypeId'. Any knowledge on the matter would be appreciated.
CREATE TABLE module(
Id INT unsigned not null auto_increment,
name VARCHAR(30) not null,
TypeId INT unsigned not null,
cSign tinyint not null,
orderId int not null,
PRIMARY KEY(Id),
KEY 'covered' ('cSign','TypeId','orderId'),
KEY 'TypeId' ('TypeId')
);

No, the indexes are different.
MySQL documentation does a good job of explaining indexes with composite keys. What is important is that the left-most columns in the indexes are different.
As a note: you should fix your code by removing the single quotes. They are incorrect in this context.

Related

mysql choose between unique key and primary key for user id

Im creating a user database ... i want to separate user - cellphone number from 'user' table and create another table for it (user_cellphone (table))
but i have a problem to select best index !
in user_cellphone table, we get user_id and cellphone number ... but all SELECT queries are more based on 'user_id' so i want to know if it's better to choose 'user_id' column as primary key or not !!!
(Also each user have only one cellphone number !)
which option of these 2 options are better ?
CREATE TABLE `user_cellphone_num` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`cellphone_country_code` SMALLINT UNSIGNED NOT NULL,
`cellphone_num` BIGINT UNSIGNED NOT NULL,
`user_id` INT UNSIGNED NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `cellphone` (`cellphone_country_code`, `cellphone_num`),
UNIQUE INDEX `user_id` (`user_id`)
)
CREATE TABLE `user_cellphone_num` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`cellphone_country_code` SMALLINT UNSIGNED NOT NULL,
`cellphone_num` BIGINT UNSIGNED NOT NULL,
`user_id` INT UNSIGNED NOT NULL,
PRIMARY KEY (`user_id`),
UNIQUE INDEX `id` (`id`),
UNIQUE INDEX `cellphone` (`cellphone_country_code`, `cellphone_num`)
)
choosing 'user_id' as primary key or just set 'user_id' as a unique key ?! is there any different here in performance ? (Im talking about when i have millions of rows)
in future im going to use some queries like this:
select u.*,cell.* FROM user AS u LEFT JOIN user_cellphone AS cell ON cell.user_id = u.id
so which one of these options give me better performance for some queries like this ?
May I offer some hard-won data design advice?
Do not use telephone numbers as any kind of unique or primary key.
Why not?
Sometimes multiple people use a single number.
Sometimes people make up fake numbers.
People punctuate numbers based on context. To my neighbors, my number is (978)555-4321. To a customer in the Netherlands it is +1.978.555.4321. Can you write a program to regularize those numbers? Of course. Can you write a correct program to do that? No. Why bother trying. Just take whatever people give you.
(Unless you work for a mobile phone provider, in which case ask your database administrator.
Read this carefully. https://github.com/google/libphonenumber/blob/master/FALSEHOODS.md
InnoDB tables are stored as a clustered index, also called an index-organized table. If the table has a PRIMARY KEY, then that is used as the key for the clustered index. The other UNIQUE KEY is a secondary index.
Queries where you look up rows by the clustered index are a little bit more efficient than using a secondary index, even if that secondary index is a unique index. So if you want to optimize for the most common query which you say is by user_id, then it would be a good idea to make that your clustered index.
In your case, it would be kind of strange to separate the cellphones into a separate table, but then make user_id alone be the PRIMARY KEY. That means that only one row per user_id can exist in this table. I would have expected that you separated cellphones into a separate table to allow each user to have multiple phone numbers.
You can get the same benefit of the clustered index if you just make sure user_id is the first column in a compound key:
CREATE TABLE `user_cellphone_num` (
`user_id` INT UNSIGNED NOT NULL,
`num` TINYINT UNSIGNED NOT NULL,
`cellphone_country_code` SMALLINT UNSIGNED NOT NULL,
`cellphone_num` BIGINT UNSIGNED NOT NULL,
PRIMARY KEY (`user_id`, `num`)
)
So a query like SELECT ... FROM user_cellphone_num WHERE user_id = ? will match one or more rows, but it will be an efficient lookup because it's searching the first column of the clustered index.
Reference: https://dev.mysql.com/doc/refman/8.0/en/innodb-index-types.html

MySQL performance using AUTO_INCREMENT on a PRIMARY KEY

I ran a comparison INSERTing rows into an empty table using MySQL 5.6.
Each table contained a column (ascending) that was incremented serially by AUTO_INCREMENT, and a pair of columns (random_1, random_2) that receive random, unique numbers.
In the first test, ascending was PRIMARY KEY and (random_1, random_2) were KEY. In the second test, (random_1, random_2) were PRIMARY KEY and ascending was KEY.
CREATE TABLE clh_test_pk_auto_increment (
ascending_pk BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, -- PK
random_ak_1 BIGINT UNSIGNED NOT NULL, -- AK1
random_ak_2 BIGINT UNSIGNED, -- AK2
payload VARCHAR(40),
PRIMARY KEY ( ascending_pk ),
KEY ( random_ak_1, random_ak_2 )
) ENGINE=MYISAM
AUTO_INCREMENT=1
;
CREATE TABLE clh_test_auto_increment (
ascending_ak BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, -- AK
random_pk_1 BIGINT UNSIGNED NOT NULL, -- PK1
random_pk_2 BIGINT UNSIGNED, -- PK2
payload VARCHAR(40),
PRIMARY KEY ( random_pk_1, random_pk_2 ),
KEY ( ascending_ak )
) ENGINE=MYISAM
AUTO_INCREMENT=1
;
Consistently, the second test (where the auto-increment column is not the PRIMARY KEY) runs slightly faster -- 5-6%. Can anyone speculate as to why?
Primary keys are often used as the sequence in which the data is actually stored. If the primary key is incremented, the data is simply appended. If the primary key is random, that would mean that existing data must be moved about to get the new row into the proper sequence. A basic (non-primary-key) index is typically much lighter in content and can be moved around faster with less overhead.
I know this to be true for other DBMS's; I would venture to guess that MySQL works similarly in this respect.
UPDATE
As stated by #BillKarwin in comments below, this theory would not hold true for MyISAM tables. As a followup-theory, I'd refer to #KevinPostlewaite's answer below (which he's since deleted), that the issue is the lack of AUTO_INCREMENT on a PRIMARY KEY - which must be unique. With AUTO_INCREMENT it's easier to determine that the values are unique since they are guaranteed to be incremental. With random values, it may take some time to actually walk the index to make this determination.

MySQL constraints involving multiple columns

I have a table in an application for which the current schema is:
CREATE TABLE quotes
(
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
quote_request_id INT UNSIGNED NOT NULL,
quote_amount DECIMAL(12, 2) NOT NULL,
accepted TINYINT UNSIGNED NOT NULL DEFAULT 0,
FOREIGN KEY (quote_request_id) REFERENCES quote_requests(id)
) Engine=InnoDB;
I want to enforce a constraint such that only one quote can be accepted for a given quote request - i.e. an UPDATE or INSERT query should fail if it attempts to modify the table such that two or more rows with the same quote_request_id value will have an accepted value of 1.
Is this possible in MySQL? Enforcing constraints such as foreign keys, uniqueness of columns other than the primary key etc. work fine, and I can find information about applying a UNIQUE constraint to multiple columns, but I can't find anything about more complex constraints which involve multiple columns.
If you want to do this without triggers, you can add another table where only accepted quotes will be stored - and you can remove the accepted column from the quotes table:
CREATE TABLE quotes
(
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
quote_request_id INT UNSIGNED NOT NULL,
quote_amount DECIMAL(12, 2) NOT NULL,
--- accepted TINYINT UNSIGNED NOT NULL DEFAULT 0, --- removed
FOREIGN KEY (quote_request_id) REFERENCES quote_requests(id)
UNIQUE KEY (quote_request_id, id) --- needed for the FK below
) Engine=InnoDB;
CREATE TABLE quotes_accepted
(
id INT UNSIGNED NOT NULL PRIMARY KEY,
quote_request_id INT UNSIGNED NOT NULL,
UNIQUE KEY (quote_request_id), --- this ensures there is only one
--- accepted quote per request
FOREIGN KEY (quote_request_id, id)
REFERENCES quotes(quote_request_id, id)
) Engine=InnoDB;
You mean you want a UNIQUE like this:
UNIQUE `quote_accepts` (`quote_request_id`, `accepted`)
where, for a repeat pair of quote_request_id & accepted, the INSERT will fail.
Answered by a_horse_with_no_name, but in a comment so it can't be accepted:
"I don't think this is possible without reverting to a trigger in MySQL because MySQL does not support partial indexes."

Having trouble with foreign key

I am trying to have categories in my budget2000 table be the foreign key to category in mainBudget. Category is not a unique number so it cannot be a primary key. When I run the code I get the famous error 1005. When I make category part of the primary key in mainBudget with id the code runs, however this will create problems later on. What can I do to make categories a foreign key. I am using mysql 5.5.
Here is my code
create table mainBudget(
id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
year Year NOT NULL,
amount double(10,2) NOT NULL,
category SMALLINT UNSIGNED NOT NULL,
primary key(id)
)ENGINE=INNODB;
create table budget2000(
id SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT,
categories SMALLINT UNSIGNED NOT NULL,
INDEX categoryNumber (categories),
subCategory SMALLINT NOT NULL,
amount FLOAT(10,2) NOT NULL,
date DATE NOT NULL,
description VARCHAR(300) NOT NULL,
primary key(id),
FOREIGN KEY (categories) REFERENCES mainBudget(category)
)ENGINE=INNODB;
category is not indexed in mainBudget. The column in the referenced table has to be indexed (or the left prefix of an index).
Incidentally, are you sure it isn't better to have an additional table category and have mainBudget.category and budget200.categories both foreign keys to this table? Your current setup looks a little odd, particularly with the referenced column in mainBudget not being unique.
Having FKs referencing non-unique columns is not standard SQL. Even when MySQL InnoDB allows this, it does not mean that it is a good idea.
Make some ER-Diagrams and normalize your tables. (Use 3.NF if nothing else forces you not to do.) Having a separate table for Category seems to be the way to go. On the other hand the naming of your exiting tables makes me thinking these should be only one table or their naming is bad.
And when this 2000 has something to do with a year or what then forget about it. You can select this easy in your Queries. Just put everything in one table no matter what year it is.
Your question/problem seems to be design-related to me.

MySQL: INDEX name (lastName, firstName)

this is the query from tutorial i read
CREATE TABLE Employee (
id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
departmentId TINYINT UNSIGNED NOT NULL
COMMENT "CONSTRAINT FOREIGN KEY (departmentId) REFERENCES Department(id)",
firstName VARCHAR(20) NOT NULL,
lastName VARCHAR(40) NOT NULL,
email VARCHAR(60) NOT NULL,
ext SMALLINT UNSIGNED NULL,
hireDate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
leaveDate DATETIME NULL,
INDEX name (lastName, firstName),
INDEX (departmentId)
)
what is the function of INDEX name (lastName, firstName) ?
Please inform me if my question is not clear.
Thank you,
GusDe
INDEX name (lastName, firstName) is creating an additional index for fast lookups when you are querying using the lastname with or without the first.
It is a composite index because it includes two columns.
Added The author of the tutorial is "guessing" that employees will often be looked up by their name or by their departmentID. That's why he or she created the two additional indexes.
-- The primary key index is automatically created for you in most dbms systems.
In real life, it is not wise to solely rely on "guessing" what columns in the tables should be indexed. Instead, use the "slow queries" log (MySQL example) to determine what queries are executing slowly and how to speed them up. Usually the answer is to add another index or two.
ps. The downside of indexes is that they increase the time required to add, update or delete data in the table since the table and the index have to be modified. A second downside of indexes is that they take up room in the db. But storage is cheap these days.
Since most databases have far more reads than writes, the speedup in querying provided by the index usually far outweighs the costs.