If you're in or around Berlin at that time, drop in.
/bb|[^b]{2}/
Never stop Grokking
innodb_file_per_table, then you have a separate .ibd file for each InnoDB table.ALTER TABLE foo DISCARD TABLESPACE; (this deletes the current .ibd file)ALTER TABLE foo IMPORT TABLESPACE;foo uses partitions, ie, its create statement was something like this:CREATE TABLE foo ( ... ) PARTITION BY ... ( PARTITION p0 ..., );In this case, you cannot discard the tablespace, and the first alter command throws an error:
mysql> ALTER TABLE foo DISCARD TABLESPACE; ERROR 1031 (HY000): Table storage engine for 'foo' doesn't have this optionI have not investigated if there are workarounds for this, but I do have a little more information on what's happening. Remember that each .ibd file is a tablespace. For a partitioned table, there are multiple .ibd files, one for each partition. The table's files look like this:
foo.frm foo.par foo#P#p0.ibd foo#P#p1.ibd ...Where
p0, p1, etc. are the partition names that you specified in the create statement. Each partition is a different tablespace and has its own tablespace id. When you create an InnoDB table without partitioning, the internal tablespace id counter is incremented by 1. When you create an InnoDB table with paritions, the internal tablespace id counter is incremented by the number of partitions. The actual tablespace id is stored in each partition's .ibd file somewhere within the first 100 bytes. I have not attempted to find out where exactly though.
INSERT INTO table (ip) VALUES (INET_ATON('$ip_address'));
And done.
slow_query_log global system variables, however since these variables are global, we need to worry about a few things.ON DUPLICATE KEY UPDATE to INSERT and UPDATE multiple rows at once. The query looks something like this: INSERT INTO table (As you can see the query gets quite complicated as the number of rows grows, but you never write this query by hand. It's generated through code in your language of choice. The only thing you have to worry about is making sure the total query size stays below your max tcp packet size. Also longer queries take longer to parse. I restrict it to about 100 rows per insert/update.
key_field, f1, f2, f3
) VALUES (
key1, f11, f21, f31
), (
key2, f12, f22, f32
), ...
ON DUPLICATE KEY UPDATE
f1 = IF(key_field=key1, f11, IF(key_field=key2, f12, IF(key_field=key3, f13, ...))),
f2 = IF(key_field=key1, f21, IF(key_field=key2, f22, IF(key_field=key3, f23, ...))),
f3 = IF(key_field=key1, f31, IF(key_field=key2, f32, IF(key_field=key3, f33, ...)))
innodb_buffer_pool_size, and that in turn was capped by the amount of RAM we had on the system.INSERT IGNORE to get this done automatically.innodb_buffer_pool_size and at that point it degraded fairly rapidly to around 150 records per second. This was unacceptable because records were coming in to the system at an average rate of 1000 per second. Since we only needed to read these records at the end of the day, it was safe to accumulate them into a text file and periodically insert them in bulk. I decided to insert 40,000 records at one time. The number I chose was arbitrary, but later tests that I ran on batches of 10K, 20K and 80K showed no difference in insert rates. With batch inserts, we managed to get an insert rate of 10,000 records per second, but this also degraded as soon as we hit the limit going down to 150 records per second.DROP TABLE is much faster than DELETE From <table> Where ..., and it also reclaims lost space. I should mention at this point that we used file_per_table as well to make sure that each table had its own file rather than use a single innodb file.CREATE TABLE ( ... ) PARTITION BY RANGE( ( time DIV 3600 ) MOD 24 ) ( Partition p0 values less than (2), Partition p1 values less than (4), Partition p2 values less than (6), Partition p3 values less than (8), Partition p4 values less than (10), Partition p5 values less than (12), Partition p6 values less than (14), Partition p7 values less than (16), Partition p8 values less than (18), Partition p9 values less than (20), Partition p10 values less than (22), Partition p11 values less than (24) );The
time field is the timestamp of incoming records, and since time always moves forward (at least in my universe), this meant that I would never write to more than 2 partitions at any point in time. Now, a little back of the envelope calculations:44M x 102 bytes = approx 4.2GB 2x for InnoDB overhead = approx 8.4GB +10% for partitioning overhead = 9.2GB /12 partitions = approx 760MB per partitionThis turned out to be more or less correct. In most cases total table size ranges between 8-10GB, sometimes it goes up to 13GB. Partition sizes range from less than 700MB to over 1GB depending on the time of day. With 4GB of RAM, we had an innodb_buffer_pool set at 2.7GB, which was good enough to store two partitions, but not good enough to work on any other tables or do anything else on the box. Boosting the RAM to 16GB meant that we could have a 12GB buffer pool, and leave 4GB for the system. This was enough for 2 partitions, even if the total number of records went up, and we could work on other tables as well.
8500 rows per second x 86400 seconds per day = 734.4 Million records per dayConsidering that before this system was redesigned it was handling about 7 Million records per day, I'd say that we did pretty well.
So if anything failed, there should have been no record in the table, yet I was seeing records that did the INSERT, but not the UPDATE, or that did the UPDATE for more than one record. Control was getting in to all the if conditions - I was getting log messages for that, but the ROLLBACK was never taking effect.
mysql_query("START TRANSACTION", $db);
$result = mysql_query("INSERT ...", $db);
if(!$result)
{
log_error($db);
mysql_query("ROLLBACK", $db);
return false;
}
$result = mysql_query("UPDATE ...", $db);
if(!$result)
{
log_error($db);
mysql_query("ROLLBACK", $db);
return false;
}
if(mysql_affected_rows($db) != 1)
{
log_error("bad update");
mysql_query("ROLLBACK", $db);
return false;
}
mysql_query("COMMIT", $db);
return true;
And immediately I started seeing errors on this line.
if(!mysql_query("START TRANSACTION", $db))
{
log_error($db);
return false;
}
Lost connection to MySQL server during querySearching on Yahoo! got me this link on the MySQL reference manual. The second last point on that page answered my question immediately:
That's exactly what I was doing. I was opening the db connection before forking, so each child inherited a copy of that connection, and as soon as one of them closed it, all the others would fail.You can also encounter this error with applications that fork child processes, all of which try to use the same connection to the MySQL server. This can be avoided by using a separate connection for each child process.
...===...