How to correctly index the following? - php

I have the following table (file_category_tbl) to represent connections between files and categories.
fileId - bigint(20)
categoryId - bigint(20)
order - int(10)
So that the files in a category can be ordered, I have an order field...
Therefore my question is what indexes would I require for optimum performance on the following:
SELECT * FROM file_category_tbl WHERE categoryId="3" ORDER BY order ASC
I have a unique index a UNIQUE (fileId ,categoryId);
As there can't be the same fileId with the same categoryId.
I have also got an index on categoryId, as this is what is being searched on.
I have also got an index on order?... but is this neccessary? as it is only doing an orderBy on this...
Kind Regards to any responder... J

As documented under ORDER BY Optimization:
In some cases, MySQL cannot use indexes to resolve the ORDER BY, although it still uses indexes to find the rows that match the WHERE clause. These cases include the following:
[ deletia ]
The key used to fetch the rows is not the same as the one used in the ORDER BY:
SELECT * FROM t1 WHERE key2=constant ORDER BY key1;
Therefore your current indexing cannot be used for performing the sort operation. However, the same page also documents:
The index can also be used even if the ORDER BY does not match the index exactly, as long as all of the unused portions of the index and all the extra ORDER BY columns are constants in the WHERE clause. The following queries use the index to resolve the ORDER BY part:
[ deletia ]
SELECT * FROM t1
WHERE key_part1=constant
ORDER BY key_part2;
Therefore a compound index over (categoryId,order) can be used for both the filter and the sort operations, which is the optimal outcome for this query.

According to my understanding, your indexing is sensible and will help towards performance of your query. But I would also suggest you to have aPrimary Key index in your table rather than only having the combined Unique Index
The reason I'm telling this is, If you want to refer to any of your records of this table, may be to delete it or do any other function, a primary key would be useful. On the other hand it might actually downgrade the performance of your query because you are requiring all the fields and now with the primary key field, you have to bring in 4 fields. As a solution for that, you can specify what columns you want in your result.
Hope this makes sense :-)

Related

MYSQL where clause slow performance on big table

I have a performance issue when working with a huge table
I add index on column using this :
ALTER table add index column;
and on the text/blob column :
alter table add index (cat(200));
My table has about 6M rows and i am working with InnoDB engine (Mysql 5.5)
This query is very fast now that i add index on "order by" column:
SELECT * from table order by column DESC LIMIT 0,40
But when I add a WHERE clause on this query its very slow and it take about 10 seconds to load even with the column "cat" index like above. //index instead of indexed
SELECT * from table WHERE cat = 'electronic' order by column DESC LIMIT 0,40
the EXPLAIN of this slow query :
EXPLAIN SELECT * from table WHERE cat = 'electronic' order by 'id' DESC LIMIT 0,40
id : 1
select_type : SIMPLE
table : product
type : ref
possible_keys: cat
key: cat
Key_len: 203
ref: const
row : 1732184
extra: using where
The query working fine with small table with 50k rows but with 6M rows its slow. Why?
Do not use prefixing, such as cat(200); it usually makes the index unusable. I have never seen a case where the Optimizer, when faced with INDEX(a(10), b), gets past a and makes any use of b.
Change cat to be VARCHAR(255). That is probably more than sufficient for "categories".
The best index (if it is possible) is
INDEX(cat, `column`)
Note that cat is in the WHERE with =. It handles the entire WHERE, so the index can move on to the ORDER BY. Hence column can be used, too. More discussion of index making .
If cat must be TEXT, then the best you can do is
INDEX(`column`)
Then the Optimizer may decide to use it for avoiding a filesort. But if there are fewer than 40 (see LIMIT) 'electronic' rows, it will take an big scan and probably be slower than not using the index. So, I am not sure that it is even worth having INDEX(column).
For this query:
SELECT t.*
FROM table t
WHERE cat = 'electronic'
ORDER BY column DESC
LIMIT 0, 40;
The best index is a composite index on table(cat, column). You can use a prefix if column is too wide: table(cat, column(200)).
The best option is to index the table, if you dont know how to do it, you can check this doc
So, when you perform the query, the mysql will start searching on the indexed values, skipping a lot of useless data for that request.

MySQL query taking a long time on Join

I have the following mysql query which takes long time
SELECT `A`.*, max(B.timestamp) as timestamp2
FROM (`A`)
JOIN `B` ON `A`.`column1` = `B`.`column1`
WHERE `column2` = 'Player'
GROUP BY `column1`
ORDER BY `timestamp2` desc
I have index on TABLE A on column1 and indexes on table B are (column1,timestamp,column2),timestamp,column1.
When i use EXPLAIN it does not use timestamp index.
Try adding an index...
... ON `B` (`column2`,`column1`,`timestamp`)
with the columns in that order.
Without any information about datatype, we're going to guess that column2 is character type (and we're going to assume that the column is in table B, given the information about the current indexes.)
Absent any information about cardinality, we're going to guess that the number of rows that satisfy the equality predicate on column2 (in the WHERE clause) is a small subset of the total rows in B.
We expect that MySQL will use of a "range" scan operation, using an index that has column2 as a leading column.
Given that the new index is a "covering" index for the query, we also expect the EXPLAIN output to show "Using index" in the Extra column.
We also expect that MySQL can use the index to satisfy the GROUP BY operation and the MAX aggregate, without requiring a filesort operation.
But we are still going to see a filesort operation, used to satisfy the ORDER BY.

Adding a Row into an alphabetically ordered SQL table

I have a SQL table with two columns:
'id' int Auto_Increment
instancename varchar
The current 114 rows are ordered alphabetically after instancename.
Now i want to insert a new row that fits into the order.
So say it starts with a 'B', it would be at around id 14 and therefore had to 'push down' all of the rows after id 14. How do i do this?
An SQL table is not inherently ordered! (It is just a set.) You would simply add the new row and view it using something like:
select instancename
from thetable
order by instancename;
I think you're going about this the wrong way. IDs shouldn't be changed. If you have tables that reference these IDs as foreign keys then the DBMS wouldn't let you change them, anyway.
Instead, if you need results from a specific query to be ordered alphabetically, tell SQL to order it for you:
SELECT * FROM table ORDER BY instancename
As an aside, sometimes you want something that can seemingly be a key (read- needs to be unique for each row) but does have to change from time to time (such as something like a SKU in a product table). This should not be the primary key for the same reason (there are undoubtedly other tables that may refer to these entries, each of which would also need to be updated).
Keeping this information distinct will help keep you and everyone else working on the project from going insane.
Try using an over and joining to self.
Update thetable
Set ID = r.ID
From thetable c Join
( Select instancename, Row_Number() Over(Order By instancename) As ID
From CollectionStatus) r On c.instancename= r.instancename
This should update the id column to the ordered number. You may have to disable it's identity first.

Unique Primary Id exchange in on mysql?

i got an sql table which contains data for a menu in the php page.
SELECT * FROM `hizlierisim` ORDER BY id LIMIT 0 , 10
it is ordered by id row.but im asked to add order control on admin panel.
So there will Up&Down Buttons to re-arrange menu items.
i guess there is two ways to do this
one is to create a row called 'order' and change sql query to:
SELECT * FROM `hizlierisim` ORDER BY `order` LIMIT 0 , 10
or
exchange id's of the columns that we wanted to move.
and still use same sql:
SELECT * FROM `hizlierisim` ORDER BY id LIMIT 0 , 10
id method seems easier but i wonder if there is a possibility to exchange id's of two columns on mysql?
Messing with primary key fields just to satisfy some arbitrary ordering requirement is a bad idea. Especially in a foreign key situation. Add an 'order' column (which is a reserved word, by the way, so use something else if you want to save yourself some pain) is the practical option.
Changing PK IDs for this sort of functionality is a very bad practice; far better to introduce an ordering column and use that to sort by. Obviously don't call it ORDER as that's a reserved word...
The id of a row should be static, a permanent unique identifier for the record, such that it can be stored as a foreign key elsewhere.
Creating the "order_id" as you suggest would be preferable. This can be changed to any value you like without a side-effect, it's for ordering, changing it only effects ordering.
In terms of "swapping" values, there isn't anything I'm aware of, you just need to code it yourself.
Either...
BEGIN TRANSACTION
UPDATE x SET order_id = NULL WHERE order_id = 11
UPDATE x SET order_id = 11 WHERE order_id = 10
UPDATE x SET order_id = 10 WHERE order_id IS NULL
COMMIT TRANSACTION
(or similar)
Or maybe something like...
UPDATE
x
SET
order_id = CASE order_id WHEN 11 then 10 ELSE 11 END
WHERE
order_id IN (10,11)
By "exchange" I assume you're talking about updating primary key values of two columns which is horrible, HORRIBLE idea - I can't stress enough how bad it is and what implications it might have. I suggest you do some reading on what primary keys are and why you should never play with them.
Add another field and update it with values 0, 1 and so on and order on that column. You can also specify multiple columns in your ORDER BY clause which allows you to order by primary key and some other column(s).

optimizing Mysql tables with index

SELECT *
FROM sms_report
WHERE R_uid = '159'
AND R_show = '1'
ORDER BY R_timestamp DESC , R_numbers
This is my query. Now it is using filesort i need to add index so that its optimized.
Below is the output of explain
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE sms_report ref R_uid,R_show R_uid 4 const 765993 Using where; Using filesort
The table is MYISAM and i have created indexes on R_smppid, R_uid, R_show, R_timedate, R_numbers
Someone adviced me on adding composite index. can you tell me which all fields should I index and how.
Try using a composite index on R_uid,R_show,R_timestamp,R_numbers - that way it should be able to find exactly the rows you are looking for in 1 index, and have the results already sorted.
EDIT - DESC may throw that optimization... but it may be worth a try
Since MySQL says possible keys == R_uid,R_show, try creating a composite index over just those two.
Try running ANALYZE TABLE sms_report; Maybe also OPTIMIZE TABLE
Also try using EXPLAIN EXTENDED ... to see if it gives you more info.
If you are only interested in some of the columns, only specify those columns instead of *. Some databases (I don't know if MySQL is one of them) can skip reading the table and return the results straight from the index if the index includes all the columns you're interested in. e.g. if you're only interested in R_uid and R_show, then doing SELECT R_uid, R_show FROM ... instead of SELECT * FROM ... could speed things up. (Again, I don't know if this applies to MySQL.)
How to add index:
alter table sms_report add index new_index (uid, show, R_timestamp, R_numbers);
How to force query to use new index
SELECT *
FROM sms_report
USE INDEX new_index
WHERE R_uid=159 AND R_show=1
ORDER BY R_timestamp DESC, R_numbers;

Categories