通过这个典型的查询,我的InnoDB表上的这些索引是正确的还是我应该更改它们?

时间:2010-10-05 17:37:50

标签: sql mysql indexing innodb myisam

我有一个像这样经常运行的php查询:

$query = 'SELECT * FROM work_orders '
    .'WHERE '    
        . "((end_time >= ?"
  . "AND start_time <= ?) "
        . "OR (start_time <= ? "
  . "AND end_time >= ? ) "
        . "OR (start_time >= ? "
  . "AND end_time <= ? )) ";

表格定义为:

CREATE TABLE IF NOT EXISTS `work_orders` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `work_order_number` varchar(32) COLLATE latin1_general_ci NOT NULL,
  `start_time` datetime NOT NULL,
  `end_time` datetime NOT NULL,
  `client_name` varchar(128) COLLATE latin1_general_ci NOT NULL,
  `location` varchar(128) COLLATE latin1_general_ci NOT NULL,
  `note` varchar(255) COLLATE latin1_general_ci DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `note_idx` (`note`),
  KEY `client_idx` (`client_name`),
  KEY `location_idx` (`location`),
  KEY `start_time_idx` (`start_time`),
  KEY `end_time_idx` (`end_time`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci AUTO_INCREMENT=1 ;

我经常对如何创建索引感到困惑。这是一个读取繁重的表,其中包含大量数据搜索,这就是为什么我将每列编入索引,但到目前为止,最常运行的查询使用开始日期和结束日期的3种组合来确定工作单​​是否属于特定列日历范围。我应该像我目前那样单独使用start_time和end_time的索引,还是应该从这两个中创建复合键?是否有更好的方法来设置索引?我甚至应该使用InnoDB吗?我根本不使用交易。

1 个答案:

答案 0 :(得分:0)

这个答案是双重的。首先,我会将索引设为:

KEY start_time_idxstart_timeend_time

但是(这是第二个问题):您的查询将无法使用任何索引。原因如下:

SELECT *
FROM work_orders
WHERE (
  (end_time >= <some-date> AND start_time <= <some-date>)
  OR
  (end_time >= <some-date> AND start_time <= <some-date>)
  OR
  (end_time >= <some-date> AND start_time <= <some-date>)
)

一旦使用OR语句,就会有效地禁用OR语句中涉及的字段的索引使用。由于您的WHERE语句没有OR语句中没有涉及的其他字段,因此不会使用任何索引。

我认为这是在PHP脚本中执行的。你有权访问phpMyAdmin吗?然后尝试运行EXPLAIN前面的查询。它会给你一些提示。

如果表包含大量数据,您可能希望将此查询更改为3个查询,每个查询仅查询单个日期范围,然后在PHP中连接结果。

/卡斯滕