Missing .frm and .idb files, cant remove table - mysql

I have a weird scenario where a technician deleted the .frm and .idb files for a table from one of my servers, fortunately it was a non critical table. I'm trying to recreate the table however when trying to use the CREATE TABLE, DROP TABLE or ALTER TABLE I get errors cos the tablespace still exists. I'm not really able to move the good tables to a new schema, drop the old schema then recreate the table that way as there are critical tables still in the schema which cannot be taken offline. Any thoughts on how I get rid of this "broken" table?

I created a test table:
mysql> use test;
mysql> create table test ( id serial primary key );
mysql> insert into test () values ();
Check that the files exist in my datadir:
$ cd /usr/local/var/mysql/test
$ ls
db.opt test.frm test.ibd
Do the unthinkable!
$ rm test.*
Now I have a catch-22 situation:
mysql> show tables;
Empty set (0.00 sec)
mysql> create table test (id serial primary key);
ERROR 1050 (42S01): Table 'test' already exists
mysql> drop table test;
ERROR 1051 (42S02): Unknown table 'test.test'
What to do?
mysql> create schema recovery;
mysql> create table recovery.test ( id serial primary key );
mysql> system cp /usr/local/var/mysql/recovery/test.frm /usr/local/var/mysql/test/
The .frm file stores table metadata in MySQL 5.x. Now that I have a .frm file, MySQL lets me query the table.
mysql> select * from test;
+----+
| id |
+----+
| 1 |
+----+
That's funny — how does it know about that row of data? Didn't I rm the .ibd file?
Answer: Files are not truly deleted while a process still has a filehandle open to it. Since I have not restarted the MySQL Server process, the .ibd tablespace file still exists, even though I unlinked it from the datadir!
Anyway, I can now drop the table. This removes the .frm and .ibd AND closes the filehandles to them, so they are truly deleted from the filesystem.
mysql> drop table test;
Query OK, 0 rows affected (0.01 sec)
And finally I can now create a new table of the same name, even with different columns.
mysql> create table test ( bar int primary key );
Query OK, 0 rows affected (0.02 sec)

Related

ERROR 1030 (HY000): Got error 168 from storage engine

Had a drive crash and recovered my mysql databases from backup. One table didn't make it and I deleted it and its associated files. (InnoDB table.) The table name was "filescan" and there are now no files in the data directory with that root name.
I am able to create and delete other table names, but not "filescan". When I try that, I get an error.
mysql> create table deleteme (id int);
Query OK, 0 rows affected (0.20 sec)
mysql> create table filescan(id int);
ERROR 1030 (HY000): Got error 168 from storage engine
mysql> drop table deleteme
-> ;
Query OK, 0 rows affected (0.03 sec)
mysql> drop table filescan;
ERROR 1051 (42S02): Unknown table 'db1.filescan'
mysql> create table filescan(id int);
ERROR 1030 (HY000): Got error 168 from storage engine
mysql>
Other answers on Stack Exchange and elsewhere seem to indicate this happens when there's a shortage of disk space. I have 130GB+ free and am able to create other tables - just not one named "filescan". I thought it might be a permissions issue, so I checked the permissions of the other files and the enclosing /data folder to ensure I have access.
Any insights?

set common DATA DIRECTORY for all partitions in a table

I'm trying to create a partitioned table on another drive with DATA DIRECTORY:
mysql> CREATE TABLE t1 (c1 INT PRIMARY KEY) DATA DIRECTORY = '/stats_tables/test/db/mysql/';
Query OK, 0 rows affected (0.03 sec)
mysql> \! ls /stats_tables/test/db/mysql/db_test/
t1.ibd
mysql> drop table t1;
Query OK, 0 rows affected (0.01 sec)
So we see that an unpartitioned table is created successfully on the drive. Now let's try the same thing with a partitioned table:
mysql> CREATE TABLE t1 (c1 INT PRIMARY KEY) DATA DIRECTORY = '/stats_tables/test/db/mysql/' PARTITION BY HASH ( c1 ) PARTITIONS 10;
Query OK, 0 rows affected (0.34 sec)
mysql> \! ls /stats_tables/test/db/mysql/db_test/
mysql> \! ls /defa_storage/test/db/mysql/db_test/t1* | xargs -n1 basename
t1.frm
t1.par
t1#P#p0.ibd
t1#P#p1.ibd
t1#P#p2.ibd
t1#P#p3.ibd
t1#P#p4.ibd
t1#P#p5.ibd
t1#P#p6.ibd
t1#P#p7.ibd
t1#P#p8.ibd
t1#P#p9.ibd
We see that in this case it's created under the regular data directory.
This has perfect explanation in the MySQL 5.5 documentation:
The DATA DIRECTORY and INDEX DIRECTORY options have no effect when defining partitions for tables using the InnoDB storage engine.
Although I use version 5.6 and there's no such a restriction mentioned in its documentation.
Anyway, is there a way to set a common DATA DIRECTORY for all my BY HASH partitions?
In the end I've found out I can actually control the created partitions in this manner:
CREATE TABLE ...
PARTITION BY HASH( ... )
(
PARTITION p0 DATA DIRECTORY = '/another/directory',
PARTITION p1 DATA DIRECTORY = '/another/directory',
PARTITION p2 DATA DIRECTORY = '/another/directory',
PARTITION p3 DATA DIRECTORY = '/another/directory',
...
);
The last part can be easily generated by any scripting language, say, Python:
max_partitions = 100
for i in range(0, max_partitions):
print("PARTITION p" + str(i) + " DATA DIRECTORY = '/another/directory',")

How to drop orphaned tables in RDS

I have the following two tables that were created due to a sql restart while doing an alter table statement:
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE '%#sql%';
TABLE_ID NAME FLAG N_COLS SPACE FILE_FORMAT ROW_FORMAT ZIP_PAGE_SIZE
1674 avails/#sql-ib1647 1 10 1396 Antelope Compact 0
1673 avails/#sql-ib1672 1 13 1395 Antelope Compact 0
How do I drop these two tables? When I do:
DROP TABLE `#sql-ib1647`
I get an error that says Unknown table 'avails.#sql-ib1647'. This is a table in Amazon RDS.
Here is a post on the issue: https://forums.aws.amazon.com/thread.jspa?messageID=570645.
MySQL DOCS:
Prefix the table with #mysql50#this should solve the problem.
DROP TABLE `#sql-ib1647`;
ERROR 1051 (42S02): Unknown table '#sql-ib1647'
Instead prefix the filename with #mysql50#, tis should work:
DROP TABLE `#mysql50##sql-ib1647`;
Query OK, 0 rows affected (0.00 sec)
That's because MySQL and MariaDB encode special characters for the
filesystem. The trick here is to prefix the tablename with #mysql50#
to prevent the server from escaping the hash mark and hyphen:

Create tables in different directories MySQL

I am attempting use MySQL to create two tables on separate drives so I can do some bench marking. I found this documentation on the Data Directory command which seems to do exactly what I need, but it is not working for me. Here is what I get:
mysql> create database test;
Query OK, 1 row affected (0.00 sec)
mysql> use test;
Database changed
mysql> show variables like 'innodb_file_per_table';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| innodb_file_per_table | ON |
+-----------------------+-------+
1 row in set (0.00 sec)
mysql> create table t1 (id int primary key, name text) data directory = '/media/ssd';
Query OK, 0 rows affected (0.03 sec)
However the table file is made in the default /var/lib/mysql/test and /media/ssd remains empty.
$ sudo ls /var/lib/mysql/test
db.opt t1.frm t1.ibd
$ ls -l /media/ssd
total 0
I have also tried other locations like /home and I get the same result so I don't believe it is a drive mounting issue. I also set the /media/ssd permissions to 777.
Any ideas why it is creating the table in the default location?
If need be can I just move the .idb file to my desired location and put a .isl in it's place?

Mysql: MyISAM table files deleted, but still inserting and selecting data. HOW?

Can someone explain me, what is happening here,
I created one table in MyISAM.
show tables -- shows it.
select command gives empty table from the table.
I delete the myisam files from location.
show tables -- does not show it.
Ok till now.
Now, still I am able to insert into table, and able to select from the table [can it happen?? how??]
Again, drop table says table does not exist.
and after this, select command says table does not exist.
Question is "where did it get inserted, and from where it is selecting the data; and after drop table call, where did it vanish?"
Server version: 5.5.38-log MySQL Community Server (GPL)
The overall sequence ..
MySQL [test]> CREATE TABLE test (id int(11) DEFAULT NULL) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Query OK, 0 rows affected (0.05 sec)
MySQL [test]> show tables;
+----------------+
| Tables_in_test |
+----------------+
| test |
+----------------+
1 row in set (0.00 sec)
MySQL [test]> select * from test;
Empty set (0.00 sec)
~~~~~~~~~~~~~~~~~~~~~~~~~
[root#localhost test]# pwd
/var/lib/mysql/test
[root#localhost test]# ll
total 16
-rw-rw---- 1 mysql mysql 8556 Dec 23 14:08 test.frm
-rw-rw---- 1 mysql mysql 0 Dec 23 14:08 test.MYD
-rw-rw---- 1 mysql mysql 1024 Dec 23 14:08 test.MYI
[root#localhost test]# rm -f *
[root#localhost test]# ll
total 0
[root#localhost test]#
~~~~~~~~~~~~~~~~~~~~~~~~~
MySQL [test]> show tables;
Empty set (0.00 sec)
MySQL [test]> insert into test values (1234);
Query OK, 1 row affected (0.00 sec)
MySQL [test]> select * from test;
+------+
| id |
+------+
| 1234 |
+------+
1 row in set (0.00 sec)
MySQL [test]> drop table test;
ERROR 1051 (42S02): Unknown table 'test'
MySQL [test]> select * from test;
ERROR 1146 (42S02): Table 'test.test' doesn't exist
On Unix, if you remove a file that another process has opened, it just removes the name from the directory, but the file still exists on disk, and the other process can continue to access it. It doesn't really go away until all processes close the file.
The MySQL daemon presumably opens the files related to a table the first time it's accessed, and then keeps the file open for as long as it can. So once it has accessed a table, removing the filename doesn't affect its operations on the contents of the table.
However, DML operations like show tables and drop tables work by accessing the directory, not the open files, so they notice the change. Then all the internal data structures are sync'ed with the filesystem.