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.
Related
I have a question about SQL indexing in my theory class. It asks me to choose which column should be indexed to optimize these 2 queries: (This is 'paper' question so I am not provided the database to test these indexes with EXPLAIN)
1, First query.
SELECT BranchName, No_Of_Copies
FROM BOOK as B, BOOK_COPIES as BC, LIBRARY_BRANCH as LB
WHERE B.BookId = BC.BookId and BC.BranchId=LB.BranchId and title ="The Lost Tribe";
I have the answer of this one, which is that BOOK.title, BOOK_COPIES.BranchId and LIBRARY_BRANCH.BranchId should be used for indexing. However, I don't really understand why BOOK.BookId and BOOK_COPIES.BookId are not chosen for indexing.
2, Second query
SELECT B.cardNo, Name, Address, COUNT(BookId,BranchId)
FROM BORROWER as B, BOOK_LOANS as BL
WHERE (BL.CardNo=B.CardNo)
GROUP BY B.CardNo, Name, Address
HAVING COUNT(BL.BookId, BranchId)>5;
Would it be optimized if I create index on BOOK_LOANS.CardNo, BORROWER.CardNo, Name and Address ?
That class needs to be updated. Using commas in JOIN is antiquated; the new style uses JOIN .. ON
The question is ambiguous -- what table contains title? I'll assume it is B.
Since the only filtering is on title, The Optimizer will pick B as the first table to look at:
B needs INDEX(title)
From B, it can reach for BC:
BC needs INDEX(BookId)
Similarly:
LB needs INDEX(BranchId)
If you are using MySQL, be aware that a PRIMARY KEY is an index. And every table needs a PRIMARY KEY. Also a PRIMARY KEY is necessarily unique. So, when I said "needs", you may find that there is already a PRIMARY KEY satisfying the need.
More: http://mysql.rjweb.org/doc.php/index_cookbook_mysql
I will quibble with the schema -- why is the "number of books" not simply a column in Books?
As for query 2, it is even less clear which table each column might be in.
Do be aware that an INDEX can contain only columns from a single table.
I have a couple of tables in a mySQL database. For simplicity I'll just show some basic fields:
Table: sources:
sourceID int not null unique primary key
trigger int not null
<other stuff>
Table: sourceBS
id not null unique primary key
sourceID int not null,
name varchar(20),
SourceID in the in the sourceBS table is a foreign key referencing its namesake in sources, with the cascade option. I have tested this: if I delete an entry in sources, the corresponding entry in sourceBS also vanishes. Good.
I want to select some stuff from a join of sources and sourceBS, filtering based on a "sources" property. This should be easy, via a join which, I think, the foreign key should render pretty efficient, so:
SELECT sources.sourceID, sourceBS.*
FROM sources
LEFT JOIN sourceBS ON sources.sourceID = sourceBS.sourceID
WHERE trigger=1;
But when this runs, each row has "NULL" for the values returned from sourceBS, even sourceBS contains entries matching the condition. I can verify this:
SELECT *
FROM sourceBS
WHERE sourceID IN (
SELECT sourceID
FROM sources
WHERE trigger=1
);
Here I get a proper set of results, i.e. non-null values. But, while this works as a proof of concept, it's no good in real life because I want to return a bunch of stuff from the "sources" table as well, and I don't want to have to run multiple queries in order to get what I want.
Returning to the join, if I replace the left join with an inner join, then no results are returned. It is as if, somehow, the "join" is simply not finding any matches in the sourceBS table, and yet they are there as the second query shows.
Why is this happening? I know that this join has a 1:M relationship, sourceBS could have multiple entries for a given entry in sources, but that should be OK. I can test exactly this type of join on other DBs, and it works.
OK, so I've solved this - it wasn't a transaction issue in the end:when I tried it on the original machine, it failed again. It was the order of the join. It appears that in my terminal I had the "ON" clause the other way round to above, that is, I was doing:
... LEFT JOIN sourceBS ON (sourceBS.blockSourceID=sources.sourceID)
which returns all the nulls. If I do it (as in the above code I pasted)
... LEFT JOIN sourceBS ON (sources.sourceID=sourceBS.sourceID
it works. When I tried it the second time last night on a new machine, I'd used the second formulation.
Guess I'd better read up on joins to understand why this happened!
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.
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.
Here is my Database structure (basic relations):
I'm attempting to formulate a one-line query that will populate the clients_ID, Job_id, tech_id, & Part_id and return back all the work orders present. Nothing more nothing less.
Thus far I've struggled to generate this Query:
SELECT cli.client_name, tech.tech_name, job.Job_Name, w.wo_id, w.time_started, w.part_id, w.job_id, w.tech_id, w.clients_id, part.Part_name
FROM work_orders as w, technicians as tech, clients as cli, job_types as job, parts_list as part
LEFT JOIN technicians as techy ON tech_id = techy.tech_name
LEFT JOIN parts_list party ON part.part_id = party.Part_Name
LEFT JOIN job_types joby ON job_id = joby.Job_Name
LEFT JOIN clients cliy ON clients_id = cliy.client_name
Apparently, once all the joining happens it does not even populate the correct foreign key values according to their reference.
[some values came out as the actual foreign key id, not even
corresponding value.]
It just goes on about 20-30 times depending on largest row of a table that I have (one of the above).
I only have two work orders created, So ideally it should return just TWO Records, and columns, and fields with correct information. What could I be doing wrong? Haven't been with MySQL too long but am learning as much as I can.
Your join conditions are wrong. Join on tech_id = tech_id, not tech_id = tech_name. Looks like you do this for all your joins, so they all need to be fixed.
I really don't follow the text of your question, so I am basing my answer solely on your query.
Edit
Replying to your comment here. You said you want to "load up" the tech name column. I assume you mean you want tech name to be part of your result set.
The SELECT part of the query is what determines the columns that are in the result set. As long as the table where the column lives is referenced in the FROM/JOIN clauses, you can SELECT any column from that table.
Think of a JOIN statement as a way to "look up" a value in one table based on a value in another table. This is a very simplified definition, but it's a good way to start thinking about it. You want tech name in your result set, so you look it up in the Technicians table, which is where it lives. However, you want to look it up by a value that you have in the Work Orders table. The key (which is actually called a foreign key) that you have in the Work Orders table that relates it to the Technicians table is the tech_id. You use the tech_id to look up the related row in the Technicians table, and by doing so can include any column in that table in your result set.