1

We are running MySQL 5.1.71-log and have a table with 2.7 million rows. Simple updates to it are regularly taking more than 10 seconds to execute.

The table structure is:

CREATE TABLE `person` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `company_id` int(10) unsigned NOT NULL,
  `status` enum('tmp','active') DEFAULT 'tmp',
  `remote_id` varchar(64) DEFAULT NULL,
  `name_last` varchar(64) DEFAULT NULL,
  `name_first` varchar(64) DEFAULT NULL,
  `sex` char(1) DEFAULT NULL,
  `dob` date DEFAULT NULL,
  `mtime` datetime NOT NULL,
  `ctime` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `ix_ID_SCHEME_LAST_FIRST_DOB` (`company_id`,`name_first`,`name_last`,`dob`),
  KEY `ix_ID_SCHEME_LAST_FIRST_DOB_GENDER` (`company_id`,`name_first`,`name_last`,`dob`,`sex`),
  KEY `ix_ID_SCHEME_MRN` (`company_id`,`remote_id`),
  CONSTRAINT `patient_ibfk_1` FOREIGN KEY (`company_id`) REFERENCES `company` (`id`)
) ENGINE=InnoDB

An update looks like

UPDATE person SET `company_id` = '1', `status` = 'tmp', `remote_id` = '12345', `name_last` = 'DOE', `name_first` = 'JOHN', `sex` = 'M', `dob` = '1980-01-01 00:00:00', `mtime` = '2014-07-11 14:16:07', `ctime` = '2014-07-10 23:00:27' WHERE id = '2693633'

Any ideas about what could be making this slow? Could it be the foreign key?

Edit 1:

show table status like 'patient'\G
*************************** 1. row ***************************
           Name: person
         Engine: InnoDB
        Version: 10
     Row_format: Compact
           Rows: 2581914
 Avg_row_length: 77
    Data_length: 199966720
Max_data_length: 0
   Index_length: 421134336
      Data_free: 5242880
 Auto_increment: 2702933
    Create_time: 2014-07-04 21:38:27
    Update_time: NULL
     Check_time: NULL
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options: 
        Comment: 
1 row in set (0.10 sec)

Edit 2:

CREATE TABLE `company` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `app_id` int(10) unsigned NOT NULL,
  `name` varchar(200) NOT NULL,
  `name_internal` varchar(200) NOT NULL,
  `license` enum('lite','full') NOT NULL DEFAULT 'lite',
  `sales_state` enum('demo','trial','paidtrial','customer','internal') DEFAULT NULL,
  `state_mtime` datetime DEFAULT NULL,
  `status` enum('tmp','active','inactive','locked') NOT NULL DEFAULT 'tmp',
  `status_mtime` datetime DEFAULT NULL,
  `beta` int(11) DEFAULT NULL,
  `mtime` datetime NOT NULL,
  `ctime` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `company_name_idx` (`name`),
  UNIQUE KEY `company_name_internal_idx` (`name_internal`),
  KEY `app_id` (`app_id`),
  CONSTRAINT `company_ibfk_1` FOREIGN KEY (`app_id`) REFERENCES `app` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2586 DEFAULT CHARSET=utf8;

and since this has a foreign key out to table app:

CREATE TABLE `app` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `type` enum('echo') NOT NULL,
  `base_url` varchar(128) NOT NULL,
  `cookie_domain` varchar(128) NOT NULL,
  `internal_url` varchar(128) NOT NULL,
  `name` varchar(128) NOT NULL,
  `login_logo` varchar(128) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `app_base_url_idx` (`base_url`),
  UNIQUE KEY `app_internal_url_idx` (`internal_url`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

Edit 3:

EXPLAIN SELECT company_id = '1', status = 'tmp', remote_id = '12345', name_last = 'DOE', name_first = 'JOHN', sex = 'M', dob = '1980-01-01 00:00:00', mtime = '2014-07-11 14:16:07', ctime = '2014-07-10 23:00:27' FROM person WHERE id = '2693633'\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: person
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
        Extra: 
1 row in set (0.00 sec)

Edit 4:

Also, two more details that might be important:

  • Queries like this (with different values) probably get executed 10-15 times per second. Most don't show up in the slow query log.
  • We have a bug/feature (not honestly sure which yet) where the exact same update gets executed in quick succession over a short (e.g. 30-second) period. Maybe once per second during that time.
  • Can you show us the output of EXPLAIN SELECT company_id = '1', status = 'tmp', remote_id = '12345', name_last = 'DOE', name_first = 'JOHN', sex = 'M', dob = '1980-01-01 00:00:00', mtime = '2014-07-11 14:16:07', ctime = '2014-07-10 23:00:27' FROM person WHERE id = '2693633'; ? – ypercubeᵀᴹ Jul 11 '14 at 17:05
  • And also add in the question the CREATE TABLE for company – ypercubeᵀᴹ Jul 11 '14 at 17:07
  • Provide also this please: SHOW TABLE STATUS LIKE 'person' – Jehad Keriaki Jul 11 '14 at 17:11
  • nb: you should not use commas around integers when they are handled as so in the database. – Sebas Jul 12 '14 at 0:13
  • nb2: your edit4 makes me think that it must be a lock problem – Sebas Jul 12 '14 at 0:14
1

It is the big number of indexed fields in each index. Remember that the update will update the table and also the index tables that hold affected rows, and in your case, all indexes will be affected.

As a side note, your indexes are 'bad'.

  1. ix_ID_SCHEME_LAST_FIRST_DOB is included in ix_ID_SCHEME_LAST_FIRST_DOB_GENDER, so it is redundant
  2. ix_ID_SCHEME_LAST_FIRST_DOB_GENDER is not useful
  3. if you provide the queries you need to run on this table, I can tell you the best indexes to have (That will also depends on data distribution, but will be better than this design :)
  • 1
    I will look for the queries that we run. What led you to determine that ix_ID_SCHEME_LAST_FIRST_DOB_GENDER is not useful? – Alan C. Jul 11 '14 at 16:58
  • 4
    I doubt that updating 4 indexes can lead to 10 seconds (for an update of 1 single row.) – ypercubeᵀᴹ Jul 11 '14 at 17:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.