2016-07-14 88 views
2

我一直在寫一個計算InnoDB表中客戶之間距離的算法的結果。例如,如果我的客戶分別爲A,B,C和d,在數據庫中的表看起來像這樣,其他列中:在這種情況下,MyISAM比mysql中的InnoDB快得多

From | To | Distance 
    A  B  344 
    A  C  274 
    A  D  182 
    B  C  338 

等等......這是很多行,我想我會達到5000萬。

其他欄是product_type和value。那些告訴我客戶B(customer_to在列中)購買了多少product_type。這意味着我有多個對,每個對取決於客戶B購買多少個產品類型。

我需要查詢來將每個客戶與他的鄰居購買的產品和價值進行分組。查詢如下所示:

select customer_from, product_type, avg(value) as opportunity 
from customer_distances 
where distance < 500 
group by customer_from, product_type 
order by opportunity desc; 

innodb表無法回答我的查詢。儘管我將net_read_timeout更改爲28800,但在查詢期間mysql連接丟失了。

我強硬它與innodb生成事務處理,而不是密集型查詢有關。所以我創建了一個MyIsam作爲引擎的新表,並插入 - 從innodb表中選擇所有記錄。

正如預期的那樣,選擇非常快(70個分類),而其他所有選擇都像count(不同的customer_from),其中幾乎是瞬時的。

只是爲了好奇,我試圖繼續在myisam表中插入距離的過程。對於我來說,當程序開始運行至少比在innodb表上工作快100倍時,對我來說是一個驚喜!

對於每個客戶,程序會插入類似3000行的東西(每個product_type的每個鄰居一個,例如300個鄰居和每個客戶的10個product_types)。用innodb表插入一個客戶需要40到60秒(約3000行)。使用myisam表格,插入3個客戶需要1秒鐘(9000行aprox)。

一些額外的信息:

因此,在總結的問題是: 爲什麼是MyISAM的那麼快帶有插入語句? 你覺得呢?

編輯1:我爲兩個表,innodb和myisam添加了創建語句。 編輯2:我刪除了一些無用信息,並在這裏和那裏合成了一些。

/* INNODB TABLE */ 
CREATE TABLE `customer_distances` (
    `customer_from` varchar(50) NOT NULL, 
    `customer_from_type` varchar(50) DEFAULT NULL, 
    `customer_from_segment` varchar(50) DEFAULT NULL, 
    `customer_from_district` int(11) DEFAULT NULL, 
    `customer_from_zone` int(11) DEFAULT NULL, 
    `customer_from_longitud` decimal(15,6) DEFAULT NULL, 
    `customer_from_latitud` decimal(15,6) DEFAULT NULL, 
    `customer_to` varchar(50) NOT NULL, 
    `customer_to_type` varchar(50) DEFAULT NULL, 
    `customer_to_segment` varchar(50) DEFAULT NULL, 
    `customer_to_district` int(11) DEFAULT NULL, 
    `customer_to_zone` int(11) DEFAULT NULL, 
    `customer_to_longitud` decimal(15,6) DEFAULT NULL, 
    `customer_to_latitud` decimal(15,6) DEFAULT NULL, 
    `distance` decimal(10,2) DEFAULT NULL, 
    `product_business_line` varchar(50) DEFAULT NULL, 
    `product_type` varchar(50) NOT NULL, 
    `customer_from_liters` decimal(10,2) DEFAULT NULL, 
    `customer_from_dollars` decimal(10,2) DEFAULT NULL, 
    `customer_from_units` decimal(10,2) DEFAULT NULL, 
    `customer_to_liters` decimal(10,2) DEFAULT NULL, 
    `customer_to_dollars` decimal(10,2) DEFAULT NULL, 
    `customer_to_units` decimal(10,2) DEFAULT NULL, 
    `liters_opportunity` decimal(10,2) DEFAULT NULL, 
    `dollars_opportunity` decimal(10,2) DEFAULT NULL, 
    `units_oportunity` decimal(10,2) DEFAULT NULL, 
    PRIMARY KEY (`cliente_desde`,`cliente_hasta`,`grupo`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

/* MYISAM TABLE */ 
CREATE TABLE `customer_distances` (
    `customer_from` varchar(50) NOT NULL, 
    `customer_from_type` varchar(50) DEFAULT NULL, 
    `customer_from_segment` varchar(50) DEFAULT NULL, 
    `customer_from_district` int(11) DEFAULT NULL, 
    `customer_from_zone` int(11) DEFAULT NULL, 
    `customer_from_longitud` decimal(15,6) DEFAULT NULL, 
    `customer_from_latitud` decimal(15,6) DEFAULT NULL, 
    `customer_to` varchar(50) NOT NULL, 
    `customer_to_type` varchar(50) DEFAULT NULL, 
    `customer_to_segment` varchar(50) DEFAULT NULL, 
    `customer_to_district` int(11) DEFAULT NULL, 
    `customer_to_zone` int(11) DEFAULT NULL, 
    `customer_to_longitud` decimal(15,6) DEFAULT NULL, 
    `customer_to_latitud` decimal(15,6) DEFAULT NULL, 
    `distance` decimal(10,2) DEFAULT NULL, 
    `product_business_line` varchar(50) DEFAULT NULL, 
    `product_type` varchar(50) NOT NULL, 
    `customer_from_liters` decimal(10,2) DEFAULT NULL, 
    `customer_from_dollars` decimal(10,2) DEFAULT NULL, 
    `customer_from_units` decimal(10,2) DEFAULT NULL, 
    `customer_to_liters` decimal(10,2) DEFAULT NULL, 
    `customer_to_dollars` decimal(10,2) DEFAULT NULL, 
    `customer_to_units` decimal(10,2) DEFAULT NULL, 
    `liters_opportunity` decimal(10,2) DEFAULT NULL, 
    `dollars_opportunity` decimal(10,2) DEFAULT NULL, 
    `units_oportunity` decimal(10,2) DEFAULT NULL, 
    PRIMARY KEY (`cliente_desde`,`cliente_hasta`,`grupo`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8; 
+0

這些表格是否相同(索引等)?並且對於可能影響性能的引擎,有單獨的服務器設置(如內存緩存大小)。 – Uueerdo

+0

您應該規範產品銷售數據。桌子沒有現在設計的意義。 – EJP

+0

相同的表,相同的服務器。 –

回答

3

插入

  • InnoDB的,默認情況下, 「承諾」 立即每個INSERT。這可以通過一次聚集100-1000行來彌補。
  • 批處理插入將加快MyISAM和InnoDB - 可能增加10倍。
  • 瞭解有關autocommitBEGIN..COMMIT

選擇

  • InnoDB的消耗比MyISAM數據更多的磁盤空間 - 通常是2倍,3倍;這會影響表掃描,您可能是
  • 對於該查詢,(customer_from,product_type,distance)上的組合索引可能會幫助這兩個引擎。

調整

  • 當運行只是的MyISAM,設置key_buffer_size的RAM和innodb_buffer_pool_size=0 20%。
  • 運行時只是 InnoDB,設置爲key_buffer_size只有10M和innodb_buffer_pool_size到RAM的70%。

規範化和節省空間

  • 較小 - >更多緩存 - >更少的I/O - >快(在任何引擎)
  • DECIMAL(10,2)不是最最好案例。考慮非貨幣FLOAT(如distance)。考慮更少的數字;處理高達99,999,999.99,並佔用5個字節。
  • 複製列通常不是一個好主意,例如customer_fromcustomer_to的10列。有一個Customers表,其中都有。
  • 你的每個緯度和縱向都是7個字節,並且有不必要的分辨率。建議latidud DECIMAL(6,4)longitud (7,4),對於總計的7個字節。 (這些給16米/52英尺分辨率。)

結果

這些建議後,50M行的表會小很多,並運行兩個引擎非常快很多。然後再次運行比較。

+0

非常感謝您的回答。我將在這裏進行更改並記錄結果。 –

+0

@DagoBorda - 還沒有結果? –