2010-06-09 86 views
2

我正在致力於一家僅通過貸款銷售產品的電子商店。我在任何類別中每頁顯示10種產品,每種產品有3種不同的價格標籤 - 3種不同的貸款類型。在測試期間一切都很順利,查詢執行時間非常完美,但今天當將更改傳輸到生產服務器時,網站在大約2分鐘內「崩潰」。用於選擇貸款類型的查詢有時會掛起約10秒鐘,而且會頻繁發生,因此它無法跟上並且其海拉緩慢。是,用於存儲數據的表具有大約2長槍記錄和每一選擇看起來像這樣:Mysql select - 提高性能

SELECT * 
FROM products_loans 
WHERE KOD IN("X17/Q30-10", "X17/12", "X17/5-24") 
AND 369.27 BETWEEN CENA_OD AND CENA_DO; 

3貸款類型和需要在CENA_OD和CENA_DO之間範圍的價格,則返回從而3排。

但因爲我需要每頁顯示10個產品,我需要運行低谷修改選擇使用OR,因爲我沒有發現任何其他的解決了這一點。我問過它here,但沒有得到答案。正如在參考文章中提到的,這必須單獨完成,因爲沒有列可以用於連接(當然價格和代碼除外,但結果非常非常糟糕)。這裏是show create table,kod和CENA_OD/CENA_DO非常索引通過INDEX。

CREATE TABLE `products_loans` (
    `KOEF_ID` bigint(20) NOT NULL, 
    `KOD` varchar(30) NOT NULL, 
    `AKONTACIA` int(11) NOT NULL, 
    `POCET_SPLATOK` int(11) NOT NULL, 
    `koeficient` decimal(10,2) NOT NULL default '0.00', 
    `CENA_OD` decimal(10,2) default NULL, 
    `CENA_DO` decimal(10,2) default NULL, 
    `PREDAJNA_CENA` decimal(10,2) default NULL, 
    `AKONTACIA_SUMA` decimal(10,2) default NULL, 
    `TYP_VYHODY` varchar(4) default NULL, 
    `stage` smallint(6) NOT NULL default '1', 
PRIMARY KEY (`KOEF_ID`), 
KEY `CENA_OD` (`CENA_OD`), 
KEY `CENA_DO` (`CENA_DO`), 
KEY `KOD` (`KOD`), 
KEY `stage` (`stage`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 

而且還選擇所有貸款類型和過濾後槽他們的PHP不工作好,因爲每種類型都有超過50K的記錄和選擇需要太多的時間,以及...

任何的IDE約提高速度感激。

編輯:

這裏是解釋

+----+-------------+----------------+-------+---------------------+------+---------+------+--------+-------------+ 
| id | select_type | table   | type | possible_keys  | key | key_len | ref | rows | Extra  | 
+----+-------------+----------------+-------+---------------------+------+---------+------+--------+-------------+ 
| 1 | SIMPLE  | products_loans | range | CENA_OD,CENA_DO,KOD | KOD | 92  | NULL | 190158 | Using where | 
+----+-------------+----------------+-------+---------------------+------+---------+------+--------+-------------+ 

我試圖將合併的指數,它提高了測試服務器的性能從0.44秒到0.06秒,我不能訪問從生產服務器儘管如此,所以我將不得不在明天嘗試。

+0

這不是問題的根源,但使用DECIMAL可能會使性能稍微降低。一旦你解決了主要的問題,如果你仍然需要更多的速度,考慮使用整數(如果必要,使用BIGINT,尤其是在64位服務器上)並處理應用程序代碼中的小數位。 – 2010-06-09 19:02:28

+0

有多少不同的KOD值以及CENA_OD和CENA_DO有多少個不同的值?你可以發佈'EXPLAIN SELECT ...'的輸出來查詢嗎? – 2010-06-09 19:02:57

+0

添加了解釋部分。 – realshadow 2010-06-09 19:34:45

回答

1

嘗試重構你的查詢關鍵詞,比如:

SELECT * FROM products_loans 
WHERE KOD IN("X17/Q30-10", "X17/12", "X17/5-24") 
AND CENA_OD >= 369.27 
AND CENA_DO <= 369.27; 

(MySQL的選擇索引的時候是不是很聰明),並檢查性能。

下一個嘗試是添加組合鍵 - (KOD,CENA_OD,CENA_DO)

下一個主要的嘗試是重構你的基地有從價格分離的產物。這應該真的有幫助。 PS:你也可以遷移到postgresql,當選擇正確的索引時,它比mysql更聰明。

+0

我會先試試這個。如果在表達式的左側有一個常量,則甚至可能不會使用索引。 在MySql上無法確定,它可能對數據庫沒有影響,但是您是否也可以限制(FETCH FIRST?)返回的行。這將爲您節省PHP處理和從DB發送結果到PHP的IO。 – AngerClown 2010-06-09 19:08:40

+0

是的,這將使用從數據庫採取一個產品的選擇,但如果我需要採取10(請參閱後引用)woudlnt是相同的(性能)? – realshadow 2010-06-09 19:34:28

2

你的問題是你正在尋找包含一個點的間隔(而不是間隔中所有點的更普通的查詢)。這些查詢不適用於標準B樹索引,因此您需要使用R樹索引。不幸的是,MySQL不允許您在列上選擇R-Tree索引,但是您可以通過將列類型更改爲GEOMETRY並使用幾何函數來檢查間隔是否包含該點來獲得所需的索引。

請參閱Quassnoi的文章Adjacency list vs. nested sets: MySQL他在這裏更詳細地解釋了這一點。用例不同,但涉及的技術是相同的。下面是文章的相關部分摘錄:

也有一定的類,它需要尋找含有已知值的所有範圍的任務:

  • 搜索在IP的IP地址範圍禁令名單
  • 日期範圍

和其他幾個人內搜索指定的日期。通過使用MySQL的R-Tree功能可以改進這些任務。

+0

確實非常好的閱讀,謝謝。 – Wrikken 2010-06-09 18:55:37

0

MySQL只能使用1個鍵。如果你總是由3列項,具體取決於列的實際數據(範圍)以下的一個很可能添加的性能嚴重金額:

ALTER TABLE products_loans ADD INDEX(KOD, CENA_OD, CENA_DO); 
ALTER TABLE products_loans ADD INDEX(CENA_OD, CENA_DO, KOD); 

注意,列的順序物!如果這不會提高性能,請給我們輸出查詢的EXPLAIN