Maverick
Maverick

Reputation: 3059

MySQL index help - which is faster?

What I'm dealing with:

I have a project which uses ActiveCollab 2, and the database structure is new to me - practically everything gets stored to a project_objects table and has a recursively hierarchical relationship:

Currently there are upwards of 450,000 records in this table and many of the queries in the code reference the name field which does NOT have an index on it. An example value might be Design or Development.

This might be an example query:

SELECT * FROM project_objects WHERE type = "Ticket" and name = "Design"

My problem:

I have a query that is taking upwards of 12-15 seconds and I have a feeling it's from that name column lacking the index and requiring the full text search. My understanding with indexes is that if I add one to the name field, it'll speed up the reads, but slow down the inserts and updates. Does the index need to get rebuilt completely every time a record is added or updated or is it just altered/appended? I don't want to optimize this query with an index if it means drastically slowing down other parts of the code base which depend on faster writes.

My question:

Assume 100 reads and 100 writes per day, which is more likely to be a faster process for MySQL - executing the above query on the above table without the index or having to rebuild the index every time a record is added?

I don't have the knowledge or authority to start running benchmarks, but I would like to offer a suggestion to the client without sounding completely novice. Thanks!

EDIT: Here is the table:

'CREATE TABLE `project_objects` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `source` varchar(50) DEFAULT NULL,
  `type` varchar(30) NOT NULL DEFAULT ''ProjectObject'',
  `module` varchar(30) NOT NULL DEFAULT ''system'',
  `project_id` int(10) unsigned NOT NULL DEFAULT ''0'',
  `milestone_id` int(10) unsigned DEFAULT NULL,
  `parent_id` int(10) unsigned DEFAULT NULL,
  `parent_type` varchar(30) DEFAULT NULL,
  `name` varchar(150) DEFAULT NULL,
  `body` longtext,
  `tags` text,
  `state` tinyint(4) NOT NULL DEFAULT ''0'',
  `visibility` tinyint(4) NOT NULL DEFAULT ''0'',
  `priority` tinyint(4) DEFAULT NULL,
  `created_on` datetime DEFAULT NULL,
  `created_by_id` smallint(5) unsigned NOT NULL DEFAULT ''0'',
  `created_by_name` varchar(100) DEFAULT NULL,
  `created_by_email` varchar(100) DEFAULT NULL,
  `updated_on` datetime DEFAULT NULL,
  `updated_by_id` smallint(5) unsigned DEFAULT NULL,
  `updated_by_name` varchar(100) DEFAULT NULL,
  `updated_by_email` varchar(100) DEFAULT NULL,
  `due_on` date DEFAULT NULL,
  `completed_on` datetime DEFAULT NULL,
  `completed_by_id` smallint(5) unsigned DEFAULT NULL,
  `completed_by_name` varchar(100) DEFAULT NULL,
  `completed_by_email` varchar(100) DEFAULT NULL,
  `comments_count` smallint(5) unsigned DEFAULT NULL,
  `has_time` tinyint(1) unsigned NOT NULL DEFAULT ''0'',
  `is_locked` tinyint(3) unsigned DEFAULT NULL,
  `estimate` float(9,2) DEFAULT NULL,
  `start_on` date DEFAULT NULL,
  `start_on_text` varchar(50) DEFAULT NULL,
  `due_on_text` varchar(50) DEFAULT NULL,
  `workflow_status` int(4) DEFAULT NULL,
  `varchar_field_1` varchar(255) DEFAULT NULL,
  `varchar_field_2` varchar(255) DEFAULT NULL,
  `integer_field_1` int(11) DEFAULT NULL,
  `integer_field_2` int(11) DEFAULT NULL,
  `float_field_1` double(10,2) DEFAULT NULL,
  `float_field_2` double(10,2) DEFAULT NULL,
  `text_field_1` longtext,
  `text_field_2` longtext,
  `date_field_1` date DEFAULT NULL,
  `date_field_2` date DEFAULT NULL,
  `datetime_field_1` datetime DEFAULT NULL,
  `datetime_field_2` datetime DEFAULT NULL,
  `boolean_field_1` tinyint(1) unsigned DEFAULT NULL,
  `boolean_field_2` tinyint(1) unsigned DEFAULT NULL,
  `position` int(10) unsigned DEFAULT NULL,
  `version` int(10) unsigned NOT NULL DEFAULT ''0'',
  PRIMARY KEY (`id`),
  KEY `type` (`type`),
  KEY `module` (`module`),
  KEY `project_id` (`project_id`),
  KEY `parent_id` (`parent_id`),
  KEY `created_on` (`created_on`),
  KEY `due_on` (`due_on`)
  KEY `milestone_id` (`milestone_id`)
) ENGINE=InnoDB AUTO_INCREMENT=993109 DEFAULT CHARSET=utf8'

Upvotes: 3

Views: 153

Answers (2)

ypercubeᵀᴹ
ypercubeᵀᴹ

Reputation: 115510

As @Ray points out, indexes do not have to be rebuilt on every Insert, Update or Delete operation. So, if you only want to improve efficuency of this (or similar) queries, add either an index on (name, type) or on (type, name).

Since you already have an index on (type) alone, I would add the first one:

ALTER TABLE project_objects 
  ADD INDEX name_type_IDX
    (name, type) ;

It may take a few seconds on a busy server but it has to be done once and then all the queries with conditions like yours will benefit. It may also improve efficiency of several other types of queries that involve name only or name and type:

WHERE name = 'Design' AND type = 'Ticket'      --- your query

WHERE name = 'Design'                          --- condition on `name` only 

GROUP BY name                                  --- group by  `name`

WHERE name LIKE 'Design%'                      --- range condition on `name` only

WHERE name = 'Design'                          --- equality condition on `name`
  AND type LIKE 'Ticket%'                      --- and range condition on `type`

WHERE name = 'Design'                          --- equality condition on `name`
GROUP BY type                                  --- and group by `type`

GROUP BY name                                  --- group by  `name`
       , type                                  --- and  `type`

Upvotes: 2

Ray
Ray

Reputation: 41408

The insert cost of adding a single point index on the name column is most likely negligible--it will probably amount to an addition of a constant time increase, probably no more that a few milliseconds. You will eat up some extra disk space, but that's usually not a concern. Nothing like the multiple seconds you're experienceing on select performance.

Add the index, enjoy the performance improvement.

BTW: Indexes aren't 'rebuilt' on every insert. They're usually implemented in B-Trees and unless you're deleting frequently, should require very little re-balancing once you get larger than a few levels (and rebalancing with little depth is pretty cheap).

Upvotes: 2

Related Questions