2010-01-25 53 views
2

在包含1500000行的MySql表上运行下面的选择大约需要5分30秒。MySql转换问题:从UNIX_TIMESTAMP到INT(11)

SELECT * FROM my_table WHERE timestamp BETWEEN UNIX_TIMESTAMP('2008-04-23 01:37:02') AND UNIX_TIMESTAMP('2008-04-23 01:37:03') 

[Executed: 25/01/10 5:32:47 EST PM ] [Execution: 231094/ms] 

转换和更换通过UNIX_TIMESTAMP功能在上面的查询所返回的值将显着地降低的持续时间:

SELECT UNIX_TIMESTAMP('2008-04-23 01:37:02'), UNIX_TIMESTAMP('2008-04-23 01:37:03') 

UNIX_TIMESTAMP('2008-04-23 01:37:02')  UNIX_TIMESTAMP('2008-04-23 01:37:03')  
---------------------------------------- ---------------------------------------- 
1208911022        1208911023        


SELECT * FROM my_table WHERE timestamp BETWEEN 1208911022 AND 1208911023 

[Executed: 25/01/10 5:58:27 EST PM ] [Execution: 11875/ms] 

的类型时间戳列是INT(11)

我们在这里不讨论索引 - 我不是数据库的所有者,但我会要求索引该列。

我想问你为什么两个查询之间的时间差异很大?

似乎从时间戳列每INT(11)值转换为通过UNIX_TIMESTAMP返回值的类型!


更新1


MySQL版本:

SELECT VERSION() 

5.1.23-rc-log 

解释结果:

EXPLAIN SELECT * FROM my_table WHERE timestamp BETWEEN UNIX_TIMESTAMP('2008-04-23 01:37:02') AND UNIX_TIMESTAMP('2008-04-23 01:37:03') 

id  select_type  table   type  possible_keys  key  key_len  ref  rows  Extra  
----- -------------- ------------- ------- ---------------- ------ ---------- ------ -------- ----------- 
1  SIMPLE   my_table  ALL  (null)   (null) (null)  (null) 15046061 Using where 

EXPLAIN SELECT * FROM my_table WHERE timestamp BETWEEN 1208911022 AND 1208911023 

id  select_type  table   type  possible_keys  key  key_len  ref  rows  Extra  
----- -------------- ------------- ------- ---------------- ------ ---------- ------ -------- ----------- 
1  SIMPLE   my_table  ALL  (null)   (null) (null)  (null) 15046061 Using where 



UPDATE 2


SELECT * FROM my_table WHERE timestamp >= UNIX_TIMESTAMP('2008-04-23 01:37:02') AND timestamp <= UNIX_TIMESTAMP('2008-04-23 01:37:03') 

[Executed: 26/01/10 10:29:52 EST AM ] [Execution: 264172/ms] 

EXPLAIN SELECT * FROM my_table WHERE timestamp >= UNIX_TIMESTAMP('2008-04-23 01:37:02') AND timestamp <= UNIX_TIMESTAMP('2008-04-23 01:37:03') 

id  select_type  table   type  possible_keys  key  key_len  ref  rows  Extra  
----- -------------- ------------- ------- ---------------- ------ ---------- ------ -------- ----------- 
1  SIMPLE   my_table  ALL  (null)   (null) (null)  (null) 15046061 Using where 

似乎> =和< =未进行任何差别 - 运行时间超过5分钟!

+1

请将'EXPLAIN SELECT * FROM my_table WHERE时间戳BETWEEN UNIX_TIMESTAMP('2008-04-23 01:37:02')和UNIX_TIMESTAMP('2008-04-23 01:37:03')'的结果和'解释SELECT * FROM my_table WHERE timestamp BETWEEN 1208911022 AND 1208911023'。这会告诉你正在使用哪些索引。 MySQL *很可能不会*在第一个查询中使用索引,* * *在第二个查询中使用索引。 – Asaph 2010-01-25 23:13:35

+0

增加了EXPLAIN计划和MySQL版本。 – 2010-01-26 15:47:40

+0

感谢您发布'EXPLAIN'语句的结果。现在我可以看到没有索引被使用。你可以发布'SHOW CREATE TABLE my_table'的结果吗?'所以我们可以看到表上有什么索引? – Asaph 2010-01-26 18:49:01

回答

2

我跑使用MySQL的BENCHMARK()功能这两个查询:

mysql> SELECT BENCHMARK(15000000, 1208911022 BETWEEN 
UNIX_TIMESTAMP('2008-04-23 01:37:02') AND UNIX_TIMESTAMP('2008-04-23 01:37:03')); 
1 row in set (33.28 sec) 

mysql> SELECT BENCHMARK(15000000, 1208911022 BETWEEN 1208911022 AND 1208911023); 
1 row in set (0.52 sec) 

看来,MySQL是不是足够聪明,分解出UNIX_TIMESTAMP()表达,即使他们应该是恒定的。 MySQL在表达式的每次迭代期间评估函数。所以使用这个函数在这个测试中大约慢了64倍。

我在Macbook 2.4GHz Intel Core 2 Duo上运行MySQL 5.1.41。

我建议您在准备查询之前将时间戳转换为它们的整数值。

0

我不是mySQL的大师,但它看起来像mySQL没有优化语句的BETWEEN部分,而是对每一行重新执行它,或者不使用列的索引集。 (我觉得这非常奇怪,看到的UNIX_TIMESTAMP操作的结果是固定的,但我没有另一种解释。)

你可以尝试使用>=<=我们需要的不是,看看这是否改变了任何时代?

+0

明天我会试试你的建议。但是,如何解释当我将固定值更快地工作? – 2010-01-26 02:37:59

+0

@Adrian S .:请运行我发布在您的问题的评论中的'EXPLAIN'语句。那些人的输出将会讲述完整的故事。 – Asaph 2010-01-26 05:12:34

0

因为它似乎不是索引或“之间”问题,所以可能正在评估UNIX_TIMESTAMP函数以便与每行进行比较。也就是说,它并不认为结果是一个常数。如果是这种情况,您可以计算运行UNIX_TIMESTAMP函数的开销1。500万次:)