MySQL defragment InnoDB tables - mysql

After running mysqltuner, I received this output:
Total fragmented tables: 284
To defragment I tried these:
1. ALTER TABLE tbl_name ENGINE=INNODB
2. Another way to perform a defragmentation operation is to use mysqldump to dump the table to a text file, drop the table, and reload it from the dump file.
Both of the methods are described in MySQL documentation.
But none of the methods helped. Mysqltuner still says that tables are fragmented.
Note: innodb_file_per_table is OFF in my configurations.
How can I defragment my InnoDB tables?

ALTER TABLE tbl_name ENGINE=INNODB
Is the only way to defragment a innodb table.
ALGORITHM=INPLACE can help us to do it online.

As of MySQL 5.5.11, you can also use ALTER TABLE tbl_name FORCE
to perform a “null” alter operation that rebuilds the table.
Previously the FORCE option was recognized but ignored.
https://dev.mysql.com/doc/refman/5.5/en/alter-table.html

I had the same issue and the solution that worked for me was doing analyze after alter:
alter table xyz engine=InnoDB;
analyze table xyz;

Related

Most common and important SQL commands that solely apply to MyIsam storage engine?

It has been recently come up into one of our discussions that moving an old legacy system using old MyISAM based MySQL deployment can't be easily replaced by an InnoDB based MySQL or MariaDB deployment. The reason that came up was that there were too many MyISAM only SQL commands all over the place. I haven't seen the code yet so I'm wondering what SQL commands where they referring to.
I only know of SEVERAL like below which are associated with table locking. It will probably work with InnoDB still in theory, but more appropriate for MyISAM , MERGE, and MEMORY storage engines which support table locking.
LOCK TABLES
UNLOCK TABLES
If there are more, or point me to a collection of it. It will be highly appreciated.
--edit--
I'll put everything else I find below this line.
MATCH (http://dev.mysql.com/doc/refman/5.5/en//fulltext-search.html)
You can LOCK TABLES for an InnoDB table too, so that's not MyISAM-specific. Though it's unnecessary to lock InnoDB tables. It's preferable to use transactions, MVCC, and SELECT...FOR UPDATE.
There are a number of configuration variables and status variables that are relevant only for MyISAM, such as key_buffer_size to dedicate some memory to caching indexes. But these are not commands.
A couple of features of MyISAM tables aren't supported by InnoDB. One is grouped auto-increment primary keys:
CREATE TABLE foo (
group_id INT,
position INT AUTO_INCREMENT,
PRIMARY KEY (group_id, position)
);
The table above increments position as you insert rows, but starts over at 1 for each distinct value of group_id. This works only in MyISAM.
CREATE FULLTEXT INDEX, and hence the MATCH()...AGAINST() query predicate are currently supported only in MyISAM. But these are being implemented for InnoDB in MySQL 5.6.
CREATE SPATIAL INDEX is supported only in MyISAM.
CHECKSUM TABLE applies only to MyISAM tables.
OPTIMIZE TABLE is in some ways specific to MyISAM, but when you run this command against an InnoDB table, it's automatically translated to a recreate + analyze operation.
CREATE TABLE options that are supported only by MyISAM:
AVG_ROW_LENGTH=nnn
DATA_DIRECTORY=path
INDEX_DIRECTORY=path
DELAY_KEY_WRITE=1
PACK_KEYS=1
ROW_FORMAT=FIXED
The MERGE storage engine can merge only MyISAM tables.
My favorite command to apply to a MyISAM table is the following. :-)
ALTER TABLE tablename ENGINE=InnoDB;
I prefer create a "temporary" table, insert/update and delete, drop the old table and than rename the new table to the old name.
otherwise you can in the last step
TRUNCATE TABLE x;
INSERT INTO x SELECT * from temp_x;

MySQL error when altering table to Fulltext

I get an error #1283 - Column 'title' cannot be part of FULLTEXT index when I try to include the columns I want to alter via FULLTEXT in my database.
ALTER TABLE users ADD FULLTEXT (`firstname`, `lastname`, `title`, `description`)
I'm not understanding why this error shows or how to go about in fixing this problem. Would be grateful for any ideas or tips.
NOTE: This post applies to old version of MySQL. Starting from
version 5.6, INNODB supports FULLTEXT index and the below code should not be used. Leaving the original answer for reference.
FULLTEXT index works only on MyISAM tables, not on InnoDB. You can check what storage enging you use by typing:
SHOW CREATE TABLE users;
then, you could ALTER the table to use MyISAM engine using this command:
ALTER TABLE users ENGINE = MyISAM;
Starting from Mysql 5.6, INNODB now supports FULLTEXT INDEX. Now I also ran into this issue when adding FULLTEXT to a table of mine and ran into multiple issues.
you need to insure your ibdata1 file is set to autoextend. http://dev.mysql.com/doc/refman/5.0/en/innodb-data-log-reconfiguration.html
I was running out of diskspace. While mysql alters a table, mysql uses tmp data and memory to do so. You need to make sure your tmp dir in you cnf file is pointing to a directory with enough space. Also, since it uses memory, it will use your Virtual Memory. Meaning your OS drive needs to have enough space. If this is not an option, create a tmp duplicate tmp table and alter that table with the fulltext and right an INSERT INTO table SELECT * FROM og_table
If your table is InnoDB then you can not use it. And need to drop it.
You can also refer to limitations of InnoDB # http://dev.mysql.com/doc/refman/5.5/en/innodb-restrictions.html
INNODB supports FULLTEXT INDEX since Mysql 5.6
To avoid errors "Column * cannot be part of FULLTEXT index"
check TEXT INCODING of your columns ;) It must be the same.

MySQL: reducing ibdata file size for MyISAM tables

My Question is actually very similar to this one and also includes a good answer for a case with InnoDB Engine tables:
https://dba.stackexchange.com/questions/8982/is-there-any-best-way-to-reduce-the-size-of-ibdata-in-mysql/8983#8983,
I have noticed that drop schema do not shrink ibdata files , so i have looked for a methods to configure the DB so that the size will be reduced after deleting a schema.
i have found many links talking about InnoDB and the way to save table per file so that the .frm file it self will contain the table data and it will be reduced.
But what happens with MyISAM tables (with more than 5G table size).
ibdata1 and MyISAM are mutually exclusive.
First thing you should do is count how many tables use both storage engines:
SELECT COUNT(1) EngineCount,engine
FROM information_schema.tables
WHERE table_schema NOT IN ('information_schema','performance_schema','mysql')
GROUP BY engine;
If SOME tables are InnoDB:
Perform my CleanUp of InnoDB
Howto: Clean a mysql InnoDB storage engine?
https://dba.stackexchange.com/questions/8982/is-there-any-best-way-to-reduce-the-size-of-ibdata-in-mysql/8983#8983
If you have only MyISAM tables and no InnoDB tables:
First, eliminate any traces of InnoDB
Do the following:
STEP01) Add this to my.cnf
[mysqld]
skip-innodb
STEP02) service mysql restart
STEP03) rm -f /var/lib/mysql/ibdata1 /var/lib/mysql/ib_logfile*
After these steps, you can perform a Compression of Each MyISAM tables like this:
For the table mydb.mytable that is MyISAM, just run one of the following:
OPTIMIZE TABLE mydb.mytable;
ALTER TABLE mydb.mytable ENGINE=MyISAM; ANALYZE TABLE mydb.mytable;
If you want to defrag all your MyISAM tables, here is a shell script to do so...
MYSQL_USER=root
MYSQL_PASS=rootpassword
MYSQL_CONN="-u${MYSQL_USER} -p${MYSQL_PASS}"
SQL="SELECT CONCAT('OPTIMIZE TABLE ',table_schema,'.',table_name,';') "
SQL="${SQL} FROM information_schema.tables "
SQL="${SQL} WHERE engine='MyISAM' AND table_schema NOT IN "
SQL="${SQL} ('information_schema','performance_schema','mysql')"
mysql ${MYSQL_CONN} -ANe"${SQL}" > GlobalMyISAMOptmizeTable.sql
less GlobalMyISAMOptmizeTable.sql
Once you trust the script visually, just run it
mysql ${MYSQL_CONN} < GlobalMyISAMOptmizeTable.sql
Give it a Try !!!
UPDATE 2012-07-25 09:52 EDT
I would like to clarify one of my suggestions for compression of MyISAM
I said earlier
OPTIMIZE TABLE mydb.mytable;
ALTER TABLE mydb.mytable ENGINE=MyISAM; ANALYZE TABLE mydb.mytable;
These commands are mechanically identical. OPTIMIZE TABLE performs a defrag of the MyISAM table and then runs ANALYZE TABLE to compute fresh index statistics.
Mechanically speaking, this is what ALTER TABLE mydb.mytable ENGINE=MyISAM; does:
CREATE TABLE mydb.mytabletmp LIKE mydb.mytable;
INSERT INTO mydb.mytabletmp SELECT * FROM mydb.mytable;
ALTER TABLE mydb.mytable RENAME mydb.mytablezap;
ALTER TABLE mydb.mytabletmp RENAME mydb.mytable;
DROP TABLE mydb.mytablezap;
As mentioned MyISAM shouldn't be using ibdata.
What are your innodb settings in your my.cnf, or in the MySQL shell type:
SHOW VARIABLES LIKE "%innodb%";
Are these variables set?
innodb_data_home_dir
innodb_data_file_path
If you are not using INNODB at all you should be able to safely remove the ibdata and ib_logfile(s) and restart MySQL. Normally though removing these without dropping the tables first will cause issues.
See How to shrink/purge ibdata1 file in MySQL
If you do have a MyISAM table over 5Gigs, it's recommended that you use INNODB anyway. (Anything over 4 Gigs).
To troubleshoot you could try and add
skip-innodb
in the my.cnf if you are not using INNODB at all.

Changing table type to InnoDB

I have a myisam only dedicated 32 GB RAM mysql server that is running on default configuration. I want to change the engine type to InnoDB of one table in order to avoid table locks. It has 50 million records and size on disk is around 15 GB. I am using mysql version 5.5
I guess I will need to add the following options and restart mysql.
innodb_buffer_pool_size=1G
innodb_log_file_size=100M
innodb_file_per_table=1
What else is considered to be necessary while changing the engine type?
You'll actually be running a command to convert each table.
It goes faster to first sort the table:
ALTER TABLE tablename ORDER BY primary_key_column;
Then, run the alter command:
ALTER TABLE tablename ENGINE = INNODB;
It might take a while if the table is really large, and it will use a lot of your CPU....
First of all check if your database supports InnoDB engine (I bet it is supported ;)):
SHOW ENGINES\G
If so, there is already default innodb related parameters in place, check them with:
SHOW VARIABLES LIKE '%innodb%'
and try to understand them and alter the to your specific needs. Even if you use the default params, you are now fine to play arround with InnoDB tables.
If you want to create only InnoDB tables, you can change your default storage engine, either for your current session with: SET storage_engine=INNODB; or in your config using default-storage-engine option.
By the way, the fastest way to convert a table to InnoDB is not the above described way. One can do the following to convert a table to InnoDB by simply inserting the data:
CREATE TABE new AS SELECT * FROM old WHERE 1<>1;
ALTER TABLE new ENGINE = INNODB;
INSERT INTO new SELECT * FROM old;
Of course you have to add the indexes you need manually, but its usually worth the time (and pain) you save compared to the ALTER TABLE ... on slightly bigger tables.

MySQL default database and how to make existing non-InnoDB become InnoDB

I am in the beginning stages of a project and I have so far been using the default MySQL database.
By the way, does the default database have name?
My question is how I can change the existing tables to be utf-8 and InnoDB without deleting the current ones and making new tables. Is there an alter table to make the table utf-8 and InnoDB?
Thanks,
Alex
MyISAM is the default Storage Engine for MySQL (until 5.5.5, at which point InnoDB became the default). There is no concept of a default database.
To make an existing table use InnoDB, use the following:
ALTER TABLE tbl_name ENGINE = InnoDB;
To change the character set of an existing table to utf8, use the following:
ALTER TABLE tbl_name CONVERT TO CHARACTER SET utf8;
If you want to play it safe with changing a table to InnoDB, I have a nice suggestion:
Create a new table as InnoDB and load it
For this example you have a MyISAM table called mytable in the mydb database. You can perform the following:
use mydb
CREATE TABLE mytable_innodb LIKE mytable;
ALTER TABLE mytable_innodb ENGINE=InnoDB;
INSERT INTO mytable_innodb SELECT * FROM mytable;
ALTER TABLE mytable RENAME mytable_myisam;
ALTER TABLE mytable_innodb RENAME mytable;
That's it. The new table is InnoDB plus you have a backup of the original table in MyISAM with its original contents and layout. You are free to perform whatever other conversions you need on the new InnoDB table.
CAVEAT
Make sure you optimize InnoDB
InnoDB performance tweaks
Howto: Clean a mysql InnoDB storage engine?
How to Safely Change InnoDB Log File Size
Major Differences Between InnoDB and MyISAM