Need MySQL key indexed? - mysql

Let say i have two tables,
for the sake of question, let's assume that they are two tables called customers and cars.
Customers
id name age
Cars
id customer_id brand_id engine cc
Do we need to index customer_id? Does it give any advantage?

like to highlight that on InnoDB, index automatically created on foreign key columns.
see innodb-foreign-key-constraints
in your case customer_id if the foreign key constraint is applied.

Yes it is, you probably want to join the customers table, you need to put a index on customer_id so the lookup can be done faster.
But like said in the comments, it depends, if you're not going to join the customers table (or do a WHERE / GROUP BY / ORDER BY etc. on it) and purely use it do display the id, it is not necassery.

Depending on your application business logic and how you will query the base, having an index on customer_id will give you a huge advantage on queries like
select * from customers join cars on customer_id = customers.id -- list all customers with their associated cars
Or even
select * from cars where customer_id = 2 -- list all cars for user 2
More generally, it is always a good idea to index foreign key constraints.

Related

how to Join only part of my first table to another table?

i have three tables:
account (which contain accounts Registered info and that Primary key is ads_id)
ads_info (which contain my advertising info and that Primary Key is ads_id)
favorite_ads (which that columns is fav_id, acc_id And ads_id) that specifies witch User Favorite which advertising.
Now i want to separate records which have acc_id = 1 from favorite_ads table and then outer-join this records with all of my ads_info table records.
can tell my any sql query do some thins like it for me?
You may try below query -
SELECT *
FROM ads_info AI
LEFT JOIN (SELECT fav_id, acc_id, ads_id
FROM favorite_ads
WHERE acc_id = 1) FA ON AI.ads_id = FA.ads_id

Efficient indexes for lookup table

I'm trying to understand the proper way to assign indexes on a lookup table. Given the following tables and sample query, what are the most efficient primary/additional indexes for the lookup table?
Table: items (id, title, etc.)
Table: categories (id, title, etc.)
Table: lookup (category_id, item_id, type, etc.)
SELECT * FROM items
INNER JOIN lookup ON
lookup.item_id=items.id AND lookup.type="items"
INNER JOIN categories ON
categories.id=lookup.category_id;
For this query:
SELECT *
FROM items i JOIN
lookup l
ON l.item_id = i.id AND l.type = 'items' JOIN
categories c
ON c.id = l.category_id;
The best indexes are probably:
lookup(type, item_id)
categories(id) (probably there already if id is a primary key)
items(id) (probably there already if id is a primary key)
Under some circumstances, this may not be a big improvement, particularly if most lookup() rows have a type of "items".
Apart from the join predicates your query only has a single filering precate (lookup.type = "items"). If this predicate has a good selectivity (i.e. it selects 5% or less of the rows) then you should use it as the first column of the index. I would do:
create index ix1 on lookup (type, item_id, category_id)
If the id columns on the table items and categories represent the primary keys, then there's nothing else to do.
The engine will probably read the lookup table using the index, and then will read the other two tables using their PK indexes.
Do not have an auto_incr id for the mapping table.
Have
PRIMARY KEY(type, item_id, category_id),
INDEX(category_id, type, item_id)
For the second index, will you need type when going from a category to an item? If not, leave it out.
More: http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table

Multivalued attributes in MySQL

I am working on a database in MySQL to show multivalued attributes. I am trying to find a way to create a parent and child table. The idea that I am working with is having an employee table and a hobby table. The hobbies in the hobby table would be considered the multivalued attributes since employees can have more than one hobby. My question would be, when creating these tables, should I use 3NF and add a 3 table to show the relation between the two or is there a way to implement this idea with simply two tables. I’m not very familiar with multivalued attributes so I need help creating the tables as far as what kind of keys each would use, as well as the end form. I believe I would need to make it in 3NF form and have the hobbies as the multivalued attribute, but have the hobby id from the hobby table as a primary key and the employee id as another primary key and then making the relational table contain both the employee id and hobby id as foreign keys referencing the other two tables. Any help or suggestions to show multivalued attributes would be greatly appreciated!
You have a table for employees already. It probably has a primary key we'll call employee_id.
You need a table for hobbies. It will need a primary key we'll call hobby_id.
Then, you need a way to relate employees and hobbies many-to-many. That's implemented with a third table, let's call it employees_hobbies. Using a name like that is a good idea, because the next guy to work on your code will recognize its purpose right away.
employees_hobbies should have two columns, employee_id and hobby_id. Those two columns together should be the composite primary key. Then, to confer a hobby on an employee, you add a row to employees_hobbies containing the two id values. If an employee drops a hobby, you delete the row.
If you want a list of employees showing their hobbies, you do this
SELECT e.name, GROUP_CONCAT(h.hobbyname) hobbies
FROM employees e
LEFT JOIN employees_hobbies eh ON e.employee_id = eh.employee_id
LEFT JOIN hobbies h ON eh.hobby_id = h.hobby_id
GROUP BY e.employee_id, e.name
Use LEFT JOIN operations here to keep employees without any hobbies (all work and no play) in your list.
If you want to find the most common five hobbies and the employees doing them, try this
SELECT COUNT(*) hobbycount, h.hobbyname,
GROUP_CONCAT(e.name ORDER BY e.name) people
FROM hobbies h
LEFT JOIN employees_hobbies eh ON h.hobby_id = eh.hobby_id
LEFT JOIN employees e ON eh.employee_id = e.employee_id
GROUP BY h.hobbyname
ORDER BY 1 DESC
LIMIT 5
This way of handling many-to-many relationships gives you all kinds of ways of slicing and dicing your data.
MySQL is made for this sort of thing and handles it very efficiently at small scale and large, opinions to the contrary notwithstanding.
(Avoid putting a surrogate primary id key into your employees_hobbies table. It adds no value.)
mva is not very good for mysql .
and best way to store it depend from price you can pay and accessibility need . if you need index , because database is big , and highly loaded , then possible you will need 2 tables .
employee( id , name )
employee_hobbies ( id , employeeid , hobbyid )
but in simplest case , or if you need good accessibility, you can just add text field to employee table , store there comma separated hobbyid , and then select by FIND_IN_SET() function .
e.q. single table
employee( id , name , MVA VARCHAR(512) )
you need be sure that all ids comma separated will fit into fields , side .
SELECT * from employee where FIND_IN_SET(some_hobbyid , MVA)
advantage of this method is less queries ,
disadvantage - may slower then 1st .
also there is advantages for high load system , when import into sphinx ... but this is another story ...

How Mysql indexes works in case of JOIN?

Suppose I have two tables patient, person
Mysql query is like below.
select fname , lname
from patient p
left join per on (per.person_id=p.person_id)
where p.account_id=2 and (per.fname like 'will%' OR per.lname like 'will%' ).
In case of this query how mysql will use index created on (p.account_id,p.person_id)
person_id is a foreign key from person table in patient table. .
I suspect you do not want LEFT. With LEFT JOIN, you are asking for account #2 whether or not he is named 'will'.
SELECT fname, lname
FROM patient p
JOIN per ON per.person_id = p.person_id
WHERE p.account_id = 2
AND (per.fname LIKE 'will% OR per.lname LIKE 'will%')
will find the full name of account #2 if it is a 'will', else return nothing.
You have not said what indexes you have, so we cannot explain your existing indexes. Please provide SHOW CREATE TABLE for each table.
For either version of the query, these indexes are the only useful ones:
p: INDEX(account_id) -- if it is not already the PRIMARY KEY
per: INDEX(person_id) -- again, if it is not already the PRIMARY KEY.
A PRIMARY KEY is a UNIQUE index.
The first index (or PK) would be a quick lookup to find the row(s) with account_id=2. The second would make the join work well. No index is useful for "will" because of the OR.
The query will look at patient first, then per, using "Nested Loop Join".
Please also provide EXPLAIN SELECT ..., so we can discuss the things I am guessing about.

MySQL multiple tables relationship (code opinion)

I have 4 tables: rooms(id, name, description), clients(id, name, email), cards(id, card_number, exp_date, client_id) and orders(id, client_id, room_id, card_id, start_date, end_date).
The tables are all InnoDB and are pretty much simple. What I need is to add relationships between them. What I did was to assign cards.client_id as a Foreign Key to db.clients and orders.client_id, orders.room_id and orders.card_id as Foreign Keys to the other tables.
My question: is this way correct and reliable? I never had the need to use Foreign Key before now and this is my first try. All the Foreign Keys are also indexes.
Also, what's the easiest way to retrieve all the information I need for db.orders ?
I need a query to output: who is the client, what's his card details, what room/s did he ordered and what's the period he's checked in.
Can I accomplish this query based on the structure I created?
You must create the FK's in all columns that relate to other tables. In your case, create on: cards.client_id, orders.client_id, orders.room_id, orders.card_id
In the case of MySQL it automatically creates indexes for these FK's.
On your select, I believe it can be the following:
SELECT * FROM orders
INNER JOIN client on client.id = orders.client_id
INNER JOIN cards on cards.client_id = client.id
INNER JOIN rooms on rooms.id = orders.room_id
I do not know what columns you need, there is only you replace the * by the columns you need, so SQL is faster.