2010-05-04 49 views
3

我正在一個具有110Mn +獨特記錄整天的mysql數據庫表上運行sql查詢。查詢龐大的數據庫表需要太多的時間在mysql

問題:每當我用「where」子句運行任何查詢時,至少需要30-40分鐘。由於我想在第二天生成大部分數據,因此我需要訪問整個數據庫表。

您能否指導我優化/重構部署模型?

網站描述:

 
mysql Ver 14.12 Distrib 5.0.24, for pc-linux-gnu (i686) using readline 5.0 
4 GB RAM, 
Dual Core dual CPU 3GHz 
RHEL 3 

my.cnf中的內容:

 
[mysqld] 
datadir=/data/mysql/data/ 
socket=/tmp/mysql.sock 

sort_buffer_size = 2000000 
table_cache = 1024 
key_buffer = 128M 
myisam_sort_buffer_size = 64M 

# Default to using old password format for compatibility with mysql 3.x 
# clients (those using the mysqlclient10 compatibility package). 
old_passwords=1 

[mysql.server] 
user=mysql 
basedir=/data/mysql/data/ 

[mysqld_safe] 
err-log=/data/mysql/data/mysqld.log 
pid-file=/data/mysql/data/mysqld.pid 
[[email protected] root]# 

數據庫表的詳細信息:

CREATE TABLE `RAW_LOG_20100504` (
    `DT` date default NULL, 
    `GATEWAY` varchar(15) default NULL, 
    `USER` bigint(12) default NULL, 
    `CACHE` varchar(12) default NULL, 
    `TIMESTAMP` varchar(30) default NULL, 
    `URL` varchar(60) default NULL, 
    `VERSION` varchar(6) default NULL, 
    `PROTOCOL` varchar(6) default NULL, 
    `WEB_STATUS` int(5) default NULL, 
    `BYTES_RETURNED` int(10) default NULL, 
    `RTT` int(5) default NULL, 
    `UA` varchar(100) default NULL, 
    `REQ_SIZE` int(6) default NULL, 
    `CONTENT_TYPE` varchar(50) default NULL, 
    `CUST_TYPE` int(1) default NULL, 
    `DEL_STATUS_DEVICE` int(1) default NULL, 
    `IP` varchar(16) default NULL, 
    `CP_FLAG` int(1) default NULL, 
    `USER_LOCATE` bigint(15) default NULL 
) ENGINE=MyISAM DEFAULT CHARSET=latin1 MAX_ROWS=200000000; 

提前感謝! Regards,

+4

您能否給我們提供一些您正在執行的示例選擇語句,這些語句顯得非常慢? – NebuSoft 2010-05-04 21:23:32

+3

在WHERE子句中可以使用的表上是否有任何索引? – 2010-05-04 21:24:16

+0

@ Nebusoft - Thnx for response select count(*),WEB_STATUS from $ table_name where CP_FLAG> 0 group by 2 order by 1 desc; @Martin:Thnx for response。我不知道如何把索引放在這個數據庫表上,因爲它不包含任何唯一的鍵。你覺得使用auto_increment幫助我嗎? – 2010-05-04 21:45:28

回答

2

將索引添加到where子句中的任何字段。主鍵必須是唯一的;唯一索引需要是唯一的,但唯一性不是索引的先決條件。

嚴重定義或不存在的索引的首要原因表現差之一,並固定這些常可導致驚人的改進

快速信息:

+0

@Frank:感謝您的回覆。你覺得從myisam改變數據庫引擎到innodb會有幫助嗎?只有myisam引擎背後的原因是在單個數據庫表中支持100Mn +記錄。 我寧願在同一張表上運行多於1個同時查詢,而不會影響其他正在進行的查詢。 – 2010-05-04 21:58:37

+0

我不完全確定要更換引擎。我使用MyISAM,但我的MySql數據庫中沒有任何表,即使接近您的大小。所以,我不是最好的人回答這樣的問題......這就是說,我相信你會看到通過簡單地添加幾個索引的改進... – 2010-05-04 22:05:15

+0

@ Bill:感謝您的迴應。您能否詳細說明以下陳述:「您可能不得不求助於預先計算您需要的COUNT(),並定期更新此統計信息。」 在給表格添加索引的同時,您是否會對my.cnf中的配置有所瞭解?這是否足夠或缺少什麼? @Frank:謝謝你的迴應。我遵循法案的迴應並添加索引來查看最終輸出的魔法。任何具體的評論w.r.t my.cnf配置? – 2010-05-04 22:26:21

9

我鼓勵您學習如何使用EXPLAIN來分析數據庫的查詢優化計劃。另請參閱Baron Schwartz的演示文稿EXPLAIN Demystified(他的幻燈片的PDF鏈接在該頁面上)。

瞭解如何創建索引 - 這與主鍵或自動增量僞碼不同。見Yoshinori Matsunobu的介紹More Mastering the Art of Indexing

您的表格可以使用CP_FLAGWEB_STATUS上的索引。

CREATE INDEX CW ON RAW_LAW_20100503 (CP_FLAG, WEB_STATUS); 

這有助於根據您的cp_flag條件查找行的子集。

然後你仍然遇到MySQL的不幸的低效率與GROUP BY查詢。它將臨時結果集複製到磁盤上的臨時文件中,並將其排序。磁盤I/O往往會導致性能下降。

您可以提高您的sort_buffer_size配置參數,直到它足夠大,MySQL可以將結果集排序在內存中而不是磁盤上。但這可能無效。

您可能不得不求助於預先計算所需的COUNT(),並定期更新此統計信息。


@Marcus的評論給了我另一個想法。您正在按網絡狀態進行分組,並且網絡狀態的一組不同值是一個相當短的列表,並且它們不會更改。因此,您可以針對每個不同的值運行單獨的查詢,並生成所需的結果,這比使用創建臨時表的GROUP BY查詢來執行排序要快得多。或者你可以運行每個狀態值的子查詢,並UNION在一起:

(SELECT COUNT(*), WEB_STATUS FROM RAW_LOG_20100504 WHERE CP_FLAG > 0 AND WEB_STATUS = 200) 
UNION 
(SELECT COUNT(*), WEB_STATUS FROM RAW_LOG_20100504 WHERE CP_FLAG > 0 AND WEB_STATUS = 404) 
UNION 
(SELECT COUNT(*), WEB_STATUS FROM RAW_LOG_20100504 WHERE CP_FLAG > 0 AND WEB_STATUS = 304) 
UNION 
...etc... 
ORDER BY 1 DESC; 

因爲你覆蓋指數包括CP_FLAGWEB_STATUS,這些查詢從來不需要在表中讀取實際行。它們只讀取索引中的條目,因爲它們可以更快地訪問,因爲(a)它們位於已排序的樹中,並且(b)如果足夠分配給key_buffer_size,它們可能會緩存在內存中。

EXPLAIN報告我想(與試驗數據的1M行)表明,該使用索引很好,不會創建一個臨時表:

+------+--------------+------------------+------+--------------------------+ 
| id | select_type | table   | key | Extra     | 
+------+--------------+------------------+------+--------------------------+ 
| 1 | PRIMARY  | RAW_LOG_20100504 | CW | Using where; Using index | 
| 2 | UNION  | RAW_LOG_20100504 | CW | Using where; Using index | 
| 3 | UNION  | RAW_LOG_20100504 | CW | Using where; Using index | 
| NULL | UNION RESULT | <union1,2,3>  | NULL | Using filesort   | 
+------+--------------+------------------+------+--------------------------+ 

Using filesort最後一行只是意味着它必須沒有索引的好處進行排序。但是對子查詢產生的三行進行排序並不重要,MySQL會在內存中進行排序。


在設計最佳數據庫解決方案時,很少有簡單的答案。很大程度上取決於您如何使用數據以及哪種查詢優先級更高。如果有一個簡單的答案適用於所有情況,那麼軟件就會默認啓用該設計,您不需要做任何事情。

您確實需要閱讀大量手冊,書籍和博客,以瞭解如何充分利用所有可用功能。


是的,我仍然建議使用索引。很明顯,這是不工作的,當你查詢1億行沒有索引的好處。

您必須明白,您必須設計有利於您希望運行的特定查詢的索引。我無法知道您剛纔在評論中描述的索引是否合適,因爲您尚未顯示您正在嘗試加速的其他查詢。

索引是一個複雜的話題。如果您在錯誤的列上定義索引,或者按錯誤的順序獲取列,則某個查詢可能無法使用該列。自1994年以來,我一直在爲SQL開發人員提供支持,而我從來沒有找到簡單明瞭的規則來解釋如何設計索引。

你好像你需要一個導師,因爲你處於一個需要很多問題回答的階段。有工作的人可以請求幫助你嗎?

+0

@Bill,COUNT(*)使用覆蓋索引嗎? – 2010-05-04 22:31:01

+0

@比爾:對不起。由於許多「添加評論」選項,我迷路了。 我嘗試使用' CREATE INDEX USER ON RAW_LOG_20100503(MSISDN,BYTES_RETURNED,REQ_SIZE); ' 但即使在41614秒之後它還沒有完成。我不得不中止查詢使用「ctrl + c」 你仍然會推薦我使用索引?它看起來像100Mn +記錄上的索引不能提供最佳性能。還有一件事,即我每天都會使用新桌子。如何在這種情況下編制索引工作? – 2010-05-05 10:21:13

+0

@比爾:我知道不會有「一種解決方案適合所有」的方法。但我想了解如何在我的情況下優化MySQL。因此請求您的寶貴意見/反饋,這將有助於我提高MySQL數據庫性能。 – 2010-05-05 11:09:46