The status of the bug is labeled as Won't fix and I can understand why in this context.
The right way would have been to run ALTER TABLE tbl_name DROP PARTITION;
because the MySQL Documentation on ALTER TABLE Partition Operations
says:
DROP PARTITION can be used to drop one or more RANGE or LIST partitions. This statement cannot be used with HASH or KEY partitions; instead, use COALESCE PARTITION (see below). Any data that was stored in the dropped partitions named in the partition_names list is discarded.
ALTER TABLE t1 DROP PARTITION p0, p1;
Once you ran ALTER TABLE tbl_name DISCARD TABLESPACE;
, the data dictionary should no longer be aware of the physical presence of the orphaned .ibd
files. However, since the bug does not reclaim the diskspace, perhaps the data dictionary entries for your tables is intact. Let's find out.
WARNING : You should run service mysql stop
and do a physical backup of /var/lib/mysql
First do this: SHOW CREATE TABLE tbl_name\G
Then, run SELECT * FROM tbl_name WHERE (stuff from partition #x) LIMIT 10;
to test the table's usability of each partition.
Once you are confortable with the table usability, you can any of the following:
REMOVE ANY PARTITION YOU WANT
ALTER TABLE tbl_name DROP PARTITION partition-name;
If you do not trust ALTER TABLE tbl_name DROP PARTITION partition-name;
, do it manually
CREATE TABLE tbl_name2 LIKE tbl_name;
ALTER TABLE tbl_name2 DROP PARTITION partition-name;
INSERT INTO tbl_name2 SELECT * FROM tbl_name WHERE (anything but stuff from partition-name)
ALTER TABLE tbl_name RENAME tbl_name9;
ALTER TABLE tbl_name2 RENAME tbl_name;
DROP TABLE tbl_name9;
DROP ALL DATA FROM PARTITION BUT KEEP PARTITION
ALTER TABLE tbl_name TRUNCATE PARTITION partition-name;
If you do not trust ALTER TABLE tbl_name TRUNCATE PARTITION partition-name;
, do it manually
CREATE TABLE tbl_name2 LIKE tbl_name;
INSERT INTO tbl_name2 SELECT * FROM tbl_name WHERE (anything but stuff from partition-name)
ALTER TABLE tbl_name RENAME tbl_name9;
ALTER TABLE tbl_name2 RENAME tbl_name;
DROP TABLE tbl_name9;
CREATE A BLANK TABLE
CREATE TABLE tbl_name2 LIKE tbl_name;
DROP TABLE tbl_name;
ALTER TABLE tbl_name2 RENAME tbl_name;
Give it a Try !!!
UPDATE 2013-05-20 18:41 EDT
I am glad you were able to drop the partition.
I have some distressing news: It is not possible to shrink ibdata1 without dumping all the data, deleting ibdata1, restarting mysql, and reloading.
Here are my past posts on how to do that safely:
What might cause the big discrepancy in disk space?
Typically this is caused by rows that have been deleted. Heaps do not reclaim space for data pages emptied by DELETE
operations unless a table lock is taken at the time of the deletion. Even then, other factors like the possibility of row-overflow data, or an enabled row-versioning isolation level can prevent space being reclaimed.
Another factor that usually has a much smaller impact on space usage is that rows with variable-length columns that expand may not fit on the original heap page, in which case the row is forwarded to another page. Forwarded rows are more usually associated with scan performance issues than pure space usage, however.
Overall, tables that experience significant deletions (without the space being reused quickly by new rows) and/or variable column updates that do not fit in place are often better configured with a clustered index. Clustered tables usually deallocate empty pages very quickly.
You can use the sys.dm_db_index_physical_stats
DMV to see physical details for a heap or index:
SELECT
DDIPS.index_id,
DDIPS.partition_number,
DDIPS.index_type_desc,
DDIPS.alloc_unit_type_desc,
DDIPS.avg_fragmentation_in_percent,
DDIPS.fragment_count,
DDIPS.avg_fragment_size_in_pages,
DDIPS.page_count,
DDIPS.avg_page_space_used_in_percent,
DDIPS.record_count,
DDIPS.avg_record_size_in_bytes,
DDIPS.forwarded_record_count
FROM sys.dm_db_index_physical_stats
(
DB_ID(),
OBJECT_ID(N'dbo.t1', N'U'),
0,
NULL,
'DETAILED'
) AS DDIPS;
The following (trivial) example shows a heap DELETE
not releasing any empty pages:
SET NOCOUNT ON;
CREATE TABLE t1 (c1 char(8000) DEFAULT 'a');
GO
INSERT INTO t1 DEFAULT VALUES;
GO 1000
-- 1000 pages allocated
SELECT
DDIPS.index_id,
DDIPS.partition_number,
DDIPS.page_count
FROM sys.dm_db_index_physical_stats
(
DB_ID(),
OBJECT_ID(N'dbo.t1', N'U'),
0,
NULL,
'DETAILED'
) AS DDIPS;
-- Delete all the data from the heap
DELETE FROM t1;
-- Still 1000 pages allocated
-- Even though the table is empty
SELECT
DDIPS.index_id,
DDIPS.partition_number,
DDIPS.page_count
FROM sys.dm_db_index_physical_stats
(
DB_ID(),
OBJECT_ID(N'dbo.t1', N'U'),
0,
NULL,
'DETAILED'
) AS DDIPS;
GO
DROP TABLE dbo.t1;
If you try the example again, but with a table lock (DELETE FROM t1 WITH (TABLOCK)
) the deletion frees all empty pages (assuming the database does not have the READ_COMMITTED_SNAPSHOT
option set to ON
etc.)
Best Answer
Rebuild the index to write out all pages freshly in the optimal way.
If you want to absolutely minimize space usage, specify
ONLINE = OFF
. Online operations add a small amount of per-row space overhead.MAXDOP = 1
can be good to reduce fragmentation. Not sure if that can help with space usage, though. I can't think of anything that a DOP of 1 might save.If the target file of the rebuild already contains fragmented freespace the newly built index/partition can turn out to be fragmented immediately. Consider building into an empty target filegroup that is pre-sized to approximately the right size.