我需要优化MYSQL查询执行订单。无论我做什么,mysql最终都会使用文件而不是使用索引。
这是我的表ddl ...(是的,在这种情况下,DAYSTAMP和TIMESTAMP列完全相同)。
CREATE TABLE DB_PROBE.TBL_PROBE_DAILY (
DAYSTAMP date NOT NULL,
TIMESTAMP date NOT NULL,
SOURCE_ADDR varchar(64) NOT NULL,
SOURCE_PORT int(10) NOT NULL,
DEST_ADDR varchar(64) NOT NULL,
DEST_PORT int(10) NOT NULL,
PACKET_COUNT int(20) NOT NULL,
BYTES int(20) NOT NULL,
UNIQUE KEY IDX_TBL_PROBE_DAILY_05 (DAYSTAMP,SOURCE_ADDR(16),SOURCE_PORT,
DEST_ADDR(16),DEST_PORT,TIMESTAMP),
KEY IDX_TBL_PROBE_DAILY_01 (SOURCE_ADDR(16),TIMESTAMP),
KEY IDX_TBL_PROBE_DAILY_02 (DEST_ADDR(16),TIMESTAMP),
KEY IDX_TBL_PROBE_DAILY_03 (SOURCE_PORT,TIMESTAMP),
KEY IDX_TBL_PROBE_DAILY_04 (DEST_PORT,TIMESTAMP),
KEY IDX_TBL_PROBE_DAILY_06 (DAYSTAMP,TIMESTAMP,BYTES)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
/*!50100 PARTITION BY RANGE (to_days(DAYSTAMP))
(PARTITION TBL_PROBE_DAILY_P20100303 VALUES LESS THAN (734200) ENGINE = InnoDB,
PARTITION TBL_PROBE_DAILY_P20100304 VALUES LESS THAN (734201) ENGINE = InnoDB,
PARTITION TBL_PROBE_DAILY_P20100305 VALUES LESS THAN (734202) ENGINE = InnoDB,
PARTITION TBL_PROBE_DAILY_P20100306 VALUES LESS THAN (734203) ENGINE = InnoDB) */;
分区是每天,我已经添加了IDX_TBL_PROBE_DAILY_06,特别是对于我正在努力工作的查询,这是:
select SOURCE_ADDR as 'Source_IP',
SOURCE_PORT as 'Source_Port',
DEST_ADDR as 'Destination_IP',
DEST_PORT as 'Destination_Port',
BYTES
from TBL_PROBE_DAILY
where DAYSTAMP >= '2010-03-04' and DAYSTAMP <= '2010-03-04'
and TIMESTAMP >= FROM_UNIXTIME(1267653600) and TIMESTAMP <= FROM_UNIXTIME(1267687228)
order by bytes desc limit 20;
解释计划如下:
+----+-------------+-----------------+---------------------------+-------+-----------------------------------------------+------------------------+---------+------+--------+-----------------------------+ | id | select_type | table |
partitions | type | possible_keys |
key | key_len | ref | rows | Extra |
+----+-------------+-----------------+---------------------------+-------+-----------------------------------------------+------------------------+---------+------+--------+-----------------------------+ | 1 | SIMPLE | TBL_PROBE_DAILY |
TBL_PROBE_DAILY_P20100304 | range |
IDX_TBL_PROBE_DAILY_05,IDX_TBL_PROBE_DAILY_06 | IDX_TBL_PROBE_DAILY_05 | 3 | NULL |
216920 | Using where; Using filesort |
+----+-------------+-----------------+---------------------------+-------+-----------------------------------------------+------------------------+---------+------+--------+-----------------------------+
我也尝试过FORCE INDEX(IDX_TBL_PROBE_DAILY_06),在这种情况下,它很乐意使用IDX_06来满足where约束,但仍然使用了一个文件:(
我无法想象分区表上的索引排序是不可能的? InnoDB在这方面与MyISAM有什么不同?我原以为InnoDBs索引+数据缓存是索引排序的理想选择。
我们将非常感谢任何帮助......我整个星期都在尝试以不同方式优化此查询,但没有取得多大成功。
答案 0 :(得分:2)
确定。看起来像交换索引中的列就行了。
我真的不知道为什么......也许别人有解释?
无论哪种方式,如果我添加索引
create index IDX_TBL_PROBE_DAILY_07 on TBL_PROBE_DAILY(BYTES,DAYSTAMP)
然后mysql偏爱IDX07(即使没有强制索引)并进行索引排序而不是文件排序。
答案 1 :(得分:0)
我看不清楚这个定义。在这里格式化:
CREATE TABLE DB_PROBE.TBL_PROBE_DAILY (
DAYSTAMP date NOT NULL,
TIMESTAMP date NOT NULL,
SOURCE_ADDR varchar(64) NOT NULL,
SOURCE_PORT int(10) NOT NULL,
DEST_ADDR varchar(64) NOT NULL,
DEST_PORT int(10) NOT NULL,
PACKET_COUNT int(20) NOT NULL,
BYTES int(20) NOT NULL,
UNIQUE KEY IDX_TBL_PROBE_DAILY_05 (DAYSTAMP,SOURCE_ADDR(16),SOURCE_PORT,
DEST_ADDR(16),DEST_PORT,TIMESTAMP),
KEY IDX_TBL_PROBE_DAILY_01 (SOURCE_ADDR(16),TIMESTAMP),
KEY IDX_TBL_PROBE_DAILY_02 (DEST_ADDR(16),TIMESTAMP),
KEY IDX_TBL_PROBE_DAILY_03 (SOURCE_PORT,TIMESTAMP),
KEY IDX_TBL_PROBE_DAILY_04 (DEST_PORT,TIMESTAMP),
KEY IDX_TBL_PROBE_DAILY_06 (DAYSTAMP,TIMESTAMP,BYTES)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
/*!50100 PARTITION BY RANGE (to_days(DAYSTAMP))
(PARTITION TBL_PROBE_DAILY_P20100303 VALUES LESS THAN (734200) ENGINE = InnoDB,
PARTITION TBL_PROBE_DAILY_P20100304 VALUES LESS THAN (734201) ENGINE = InnoDB,
PARTITION TBL_PROBE_DAILY_P20100305 VALUES LESS THAN (734202) ENGINE = InnoDB,
PARTITION TBL_PROBE_DAILY_P20100306 VALUES LESS THAN (734203) ENGINE = InnoDB) */;
查询:
select SOURCE_ADDR as 'Source_IP',
SOURCE_PORT as 'Source_Port',
DEST_ADDR as 'Destination_IP',
DEST_PORT as 'Destination_Port',
BYTES
from TBL_PROBE_DAILY
where DAYSTAMP >= '2010-03-04' and DAYSTAMP <= '2010-03-04'
and TIMESTAMP >= FROM_UNIXTIME(1267653600) and TIMESTAMP <= FROM_UNIXTIME(1267687228)
order by bytes desc limit 20;
我怀疑问题是您的查询包含两个范围查询。根据我的经验,MySQL无法优化它遇到的第一个范围查询,因此就其而言,任何以DAYSTAMP开头的索引都等同于任何其他索引。
解释中的线索是密钥长度:这表明实际使用了多少索引值。即使强制它使用您想要的索引,它也可能是相同的值(3)。
答案 2 :(得分:0)
在始终强制文件排序的位置使用开放式相等。简而言之,一个开放式的&lt;或者&gt;使MySQL获取行并对它们进行排序以消除不匹配查询的行。如果逻辑上这个查询可以改变到一个范围内(在时间戳X和时间戳Y之间)那么MySQL可以使用那些书挡值直接从索引获得结果,然后如果你仍然想要返回已经排序的文件排序,如果你只想要匹配值
答案 3 :(得分:0)
交换确实有效,因为
如果在可用键的最左前缀(例如,ORDER BY key_part1,key_part2)上进行排序或分组,则对表进行排序或分组。如果所有关键部分后面都是DESC,则按相反顺序读取密钥。请参见第8.3.1.11节“优化顺序”和第8.3.1.12节“GROUP BY优化”。