2010-01-25 79 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萬次:)