How to create an index on two fields within MYSQL - mysql

Currently I have a MYSQL query that's under performing. I need to create an index on two fields within my query: cancel and complete.
What is the best way to perform this?
SELECT* FROM table WHERE cancel != 'CANCEL' AND complete IN ('COMPLETE','TAKEN_BACK')

To create a multi-column index, but the column names in parentheses.
ALTER TABLE table
ADD INDEX (cancel, complete);
This is equivalent to
CREATE INDEX table_cancel_complete_ix
ON table (cancel, complete);
CREATE INDEX requires you to give a name to the index, it's optional with ALTER TABLE (it will be assigned a default name).

To add an index over more than one column (aka multi-column index or composite index), use this syntax:
ALTER TABLE your_table
ADD INDEX (cancel, complete);
However, you might want to make sure this is the reason for your statement to be underperforming. Take a look into the manual to dig deeper into this.

Related

Table traversing with multiple operations in ALTER TABLE

Some databases, like MySQL [1] and PostgreSQL [2], support bundling of certain compatible ALTER TABLE statements (as non-standard SQL).
For example we can have:
ALTER TABLE `my_table`
DROP COLUMN `column_1`,
DROP COLUMN `column_2`,
...
or
ALTER TABLE
MODIFY `column_1` ... ,
MODIFY `column_2` ... ,
instead of having individual statements:
ALTER TABLE `my_table` DROP COLUMN `column_1`;
ALTER TABLE `my_table` DROP COLUMN `column_2`;
or
ALTER TABLE `my_table` MODIFY `column_1` ... ;
ALTER TABLE `my_table` MODIFY `column_2` ... ;
etc
For comparison of the same feature, PostgreSQL [2], which also implements this, will perform all operations in a single scan:
The main reason for providing the option to specify multiple changes in a single ALTER TABLE is that multiple table scans or rewrites can thereby be combined into a single pass over the table.
Although for DROP COLUMN specifically it will often not even need do that:
The DROP COLUMN form does not physically remove the column, but simply makes it invisible to SQL operations...
Questions:
Would the multi-column statement result in traversing all the rows just once and performing all changes needed?
How does MySQL actually perform DROP COLUMN? Does it also "hide" the columns first, or does it delete the data straight away?
Assumptions:
Using InnoDB
No indexes/complex defaults are involved in any of the columns we want to change/drop (so basically changes that would not require a temporary table when run as individual alter statements)
References:
[1] MySQL ALTER TABLE docs
[2] PostgreSQL ALTER TABLE docs
MySQL's InnoDB:
(This does not really answer the Questions, but provides a little more insight in the the bigger question of ALTER.)
If any of the alters needs to copy the table over, you are probably better off putting all alters into the same statement. Changing the PRIMARY KEY, for example, requires rebuilding the data that is clustered with the PK.
Some alters can be achieved by simply altering the schema; these are virtually instantaneous, and could be done via separate alter statements. Adding an option to ENUM was implemented long ago.
Some alters need some form of scan, but can do it "in the background". DROP INDEX can be done by quickly "hiding" it, then freeing up the BTree in the background.
I have left out a grey area in which you batch 'simple' alters. One would hope that ALTER is smart enough to simply go through them quickly, rather than deciding to copy the table over.
I got some useful feedback but decided to respond to my own question to provide a more concrete set of answers.
Would the multi-column statement result in traversing all the rows just once and performing all changes needed?
Yes, if the alter statement results in rebuilding the table then it only needs to do it once.*
* This answer comes from my own testing and other mostly anecdotal evidence (including #Uueerdo 's in this post). It would be useful to have some official docs for this...
How does MySQL actually perform DROP COLUMN? Does it also "hide" the columns first, or does it delete the data straight away?
MySQL will rebuild the table in place (rather than create a copy or just change metadata) for most column operations. Each specific case can be found in the Online DDL docs for InnoDB.
A few operations like renaming a column or setting a default value will just alter metadata, so they don't require a table rebuild.
However, dropping a column DOES require a full table rebuild.

Clarification on MySQL 5.6 using IN PLACE alter table for adding/dropping the same index

From the docs:
An ALTER TABLE statement that contains DROP INDEX and ADD INDEX
clauses that both name the same index uses a table copy, not Fast
Index Creation.
This is a bit unclear to me. Is it talking about the NAME of the index? Can someone give an example of a query in which MySQL resorts to a table copy?
Indeed, it sounds like this line is about:
An (One, single) ALTER TABLE statement
that contains (both) a DROP INDEX and an ADD INDEX clause
and both clauses name the same index
and states that such a statement uses a table copy, not Fast Index Creation.
Such a statement would be:
ALTER TABLE MyTable
DROP INDEX MyIndex
ADD INDEX MyIndex(MyColumn);
The documentation is not really clear about the reason behind this, but I think the database want to create an index first and then drop the other index, so the statement by itself can more easily be made atomic. (Creating the index might fail.) If the index name itself is used in the storage as well, that order of first creating then dropping would give a conflict.
After all, fast index creation is a relatively new feature, so they might improve this over time.

Full text search index independent of the table

In SQLite, we can create full text search indices as new objects, like so
CREATE VIRTUAL TABLE search_data USING fts4;
INSERT INTO search_data (description) select description from data;
In MySQL, the only way to do the same seems to be to alter the existing table like so
ALTER TABLE data ADD FULLTEXT(description);
What I am looking for is a way to create the full text index in MySQL as a new independent object without having to duplicate the data of the tables (like I can do in SQLite).
How can I do that?
You can give a name to an index, but the name is valid only within the table (e.g. you can have two indexes with the same name in if they are in different tables). Indexes don't have "global" names.
If you don't want to use ALTER TABLE you can use CREATE INDEX, for example:
create fulltext index INDEXNAME on TABLENAME (COLUMN);

How do I keep a MySQL Fulltext Index up to date?

Creating an index MySQL
After I have added the FULLTEXT index, how do I keep it up to date?
Added it this way : ALTER TABLE search_index ADD FULLTEXT(si_fulltext)
Tried to update it like this :
ALTER TABLE search_index MODIFY FULLTEXT(si_fulltext)
ALTER TABLE search_index CHANGE FULLTEXT(si_fulltext)
Thanks,
Joe
Unless you disabled the index, the server should be keeping the index up to date as data changes in the column. If you'd like to explore what is in the index, you can use the myisam_ftdump utility:
http://dev.mysql.com/doc/refman/5.0/en/myisam-ftdump.html
It's updated automatically whenever data is inserted, updated or deleted form search_index.

Alter a live table to make a key non-unique

I saw some other questions related to this, but they were not MySQL.
The database is a live database, so I don't want to delete and recreate the table. I simply want to make a column no longer unique, which is less permissive in nature so it shouldn't cause any problems.
If your column was defined unique using UNIQUE clause, then use:
ALTER TABLE mytable DROP INDEX constraint_name
, or, if your constraint was implicitly named,
ALTER TABLE mytable DROP INDEX column_name
If it was defined unique using PRIMARY KEY clause, use:
ALTER TABLE mytable DROP PRIMARY KEY
Note, however, that if your table is InnoDB, dropping PRIMARY KEY will result in implicit recreation of your table and rebuilding all indexes, which will lock the table and may make it inaccessible for quite a long time.
These are instructions for phpmyadmin app (if you are using phpMyAdmin) ::
In a some cases, the developer (you) may not want to drop it but rather just modify the "uniqueness" to "not-unique".
Steps :
Go to the table in context, where you want to make the modification
Click on the "Structure" tab (mostly next to Browse)
Look for the "+Indexes" link, just under the columns. Yeah... now click it
Now you can see all the "Indexes" and you can now click on the "DROP" button or link to modify.
Answer was found here :
Source : https://forums.phpfreaks.com/topic/164827-phpmyadmin-how-to-make-not-unique/
Just DROP the unique index. There shouldn't be a problem with the fact that it is a live DB. If it is a really large table, you may block some queries temporarily while the index is removed. But that should only happen if you were adding an index.
ALTER TABLE table_name DROP INDEX index_name;
Although the accepted answer is incorrect (see comments), the suggested workaround is possible. But it is not correct too, at least for a "live table", as asked.
To lower the impact you should create a new index at first, and then delete the old one:
ALTER TABLE mytable ADD INDEX idx_new (column);
ALTER TABLE mytable DROP INDEX idx_old;
This avoids using the table (column) without index at all, which can be quite painful for clients and the MySQL itself.
MySQL requires indexes on foreign keys and referenced keys so that foreign key checks can be fast (MySQL Manual).
If the unique key that you want to make non-unique is used by a foreign key constraint, then you'll get an error when dropping it. You will have to recreate it on the same line:
alter table mytable drop KEY myUniqueKey, add key myUniqueKey (myColumn);