2012-09-09 45 views
5

Tôi đang làm việc trên Hệ thống có nhiều yêu cầu Cập nhật, Chèn và Xóa. Đó là lý do tại sao tôi chọn INNODB là nguyên nhân của Công cụ lưu trữ của tôi trong Khóa hàng. Chúng tôi đang cập nhật 60.000 Bản ghi mỗi 10 phút. Và chúng tôi đang sử dụng Gearman để parallise Công việc của chúng tôi trên các máy chủ khác nhau. Mã bằng PHP và chúng tôi đang sử dụng Zend Framework.Tôi làm gì sai với Khóa INNODB?

Vì vậy, hãy bắt đầu với mô tả sự cố của chúng tôi. Chúng tôi đang ghi lại các lỗi và gần như mỗi 5 - 20 phút một lỗi xảy ra.

SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded; try restarting transaction 

đơn giản mở rộng "khóa thời gian chờ đợi" isnt hữu ích cho chúng ta, bởi vì chúng tôi cố gắng cập nhật càng nhanh càng tốt.

Để biết thêm thông tin tôi đã thực hiện SHOW INNODB STATUS\G. Một điều khiến tôi hỏi - những gì mà hack?

---TRANSACTION 0 18126657, ACTIVE 54 sec, process no 16154, 
OS thread id 47956454176512 fetching rows, thread declared inside InnoDB 68 mysql tables in use 1, 
locked 1 1204 lock struct(s), heap size 112624, 65338 row lock(s), undo log entries 44 
MySQL thread id 3331522, query id 103362521 [ServerIP] [USER] Updating 
UPDATE userproducts SET lowest_price=16.96, last_lowest_price_update='2012-09-09 20:07:30' WHERE product_id LIKE 'XXX' 

65388 Hàng bị khóa, vì Bản cập nhật đơn giản này? Hay tôi chỉ bỏ lỡ điều gì đó? Theo mã PHP đã thực hiện cập nhật này.

$this->db->beginTransaction(); 

    try { 
     for($i = 0; $i < count($products); $i++) 
     { 
      if(isset($products[$i]['price_total_end'])) 
      { 
       if(count($products[$i]['price_total_end']) > 1) 
       { 
        $this->db->query("UPDATE userproducts SET lowest_price=".$products[$i]['price_total_end'][1].", last_lowest_price_update='".date("Y-m-d H:i:s", time())."' WHERE product_id LIKE '".$products[$i]['p_id']."'"); 
       } elseif(count($asin[$i]['price_total_end']) == 1) { 
        $this->db->query("UPDATE userproducts SET lowest_price=-1, last_lowest_price_update='".date("Y-m-d H:i:s", time())."' WHERE product_id LIKE '".$products[$i]['p_id']."'"); 
       } 
      } 
     } 
     $this->db->commit(); 
    } catch (Exception $e) { 
     $this->db->rollBack(); 
     echo $e->getMessage(); 
    } 

Sản phẩm Array $ có trong mục 50 cấp đầu tiên của anh ấy. Vì vậy, số lượng đếm cho đến khi 50 mà không nên là nhiều, hoặc là điều này không hoàn toàn vô lý? Điều tiếp theo mà không nên quên là, rằng wie có 20 công nhân có thể thực hiện truy vấn này đồng thời.

Thông tin quan trọng cuối cùng - tôi nghĩ - là mysql_report.

MySQL 5.1.63-0+squeeze1 uptime 13 9:11:39  Sun Sep 9 20:44:50 2012 

__ Key ___ 
Buffer used 55.00k of 16.00M %Used: 0.34 
    Current  2.92M   %Usage: 18.28 
Write hit  99.95% 
Read hit  100.00% 


__ Questions ___ 
Total   103.61M 89.6/s 
    DMS   90.73M 78.5/s %Total: 87.57 
    Com_   8.57M  7.4/s   8.27 
    COM_QUIT  3.34M  2.9/s   3.22 
    QC Hits  922.81k  0.8/s   0.89 
    +Unknown  46.70k  0.0/s   0.05 
Slow 2 s  9.33M  8.1/s   9.00 %DMS: 10.28 Log: ON 
DMS   90.73M 78.5/s   87.57 
    INSERT  60.63M 52.4/s   58.51   66.82 
    UPDATE  17.80M 15.4/s   17.17   19.61 
    DELETE  9.55M  8.3/s   9.22   10.53 
    SELECT  2.76M  2.4/s   2.66   3.04 
    REPLACE   0  0/s   0.00   0.00 
Com_   8.57M  7.4/s   8.27 
    set_option 3.40M  2.9/s   3.28 
    show_fields 2.88M  2.5/s   2.78 
    begin   1.13M  1.0/s   1.09 


__ SELECT and Sort ____ 
Scan   3.60M  3.1/s %SELECT: 130.54 
Range    47  0.0/s   0.00 
Full join   24  0.0/s   0.00 
Range check   0  0/s   0.00 
Full rng join  1  0.0/s   0.00 
Sort scan  24.32k  0.0/s 
Sort range  1.69M  1.5/s 
Sort mrg pass  0  0/s 


__ Query Cache ___ 

Memory usage 1.05M of 16.00M %Used: 6.57 
Block Fragmnt 4.55% 
Hits   922.81k  0.8/s 
Inserts   2.11M  1.8/s 
Insrt:Prune 2.36k:1  1.8/s 
Hit:Insert  0.44:1 


__ Table Locks ____ 
Waited   658  0.0/s %Total: 0.00 
Immediate  90.73M 78.5/s 


__ Tables ___ 
Open    128 of 128 %Cache: 100.00 
Opened   3.95k  0.0/s 


__ Connections __ 
Max used   301 of 300  %Max: 100.33 
Total   3.34M  2.9/s 


__ Created Temp ___  
Disk table  2.88M  2.5/s 
Table   2.89M  2.5/s Size: 32.0M 
File    5  0.0/s 


__ Threads ___  
Running   21 of 168 
Cached    6 of 8  %Hit: 97.09 
Created  97.29k  0.1/s  
Slow    0  0/s 


__ Aborted ___  
Clients   2.45k  0.0/s 
Connects  2.75k  0.0/s 


__ Bytes ___  
Sent   11.04G 9.5k/s 
Received  23.13G 20.0k/s 

__ InnoDB Buffer Pool _____  
Usage   82.86M of 1.46G %Used: 5.52  
Read hit  100.00%  
Pages  
    Free   90.70k   %Total: 94.48  
    Data   4.92k      5.12 %Drty: 4.07  
    Misc   386      0.40 
    Latched   0      0.00  
Reads   610.88G 528.3k/s 
    From file  816  0.0/s   0.00 
    Ahead Rnd   3  0.0/s  
    Ahead Sql  27  0.0/s  
Writes  614.37M 531.3/s  
Flushes  10.07M  8.7/s 
Wait Free   0  0/s 


__ InnoDB Lock ___ 
Waits   837060  0.7/s  
Current   19 
Time acquiring 
    Total  157140176 ms 
    Average  18772 ms 
    Max   59096 ms 


__ InnoDB Data, Pages, Rows __  
Data 
    Reads   919  0.0/s 
    Writes  11.96M 10.3/s 
    fsync   6.26M  5.4/s  
    Pending 
    Reads   0 
    Writes   0 
    fsync   0 

Pages 
    Created  39.41k  0.0/s  
    Read   2.64k  0.0/s 
    Written  10.07M  8.7/s  

Rows 
    Deleted  40.82M 35.3/s 
    Inserted  42.90M 37.1/s 
    Read  540.45G 467.4k/s  
    Updated  47.48M 41.1/s 

Vì vậy, để quay trở lại trên khắp Câu hỏi. Tại sao chúng ta luôn nhận được lỗi chờ thời gian chờ khóa 1205?

CẬP NHẬT: Tôi đã thử một vài thứ khác. Đầu tiên, tôi đã thay đổi INSERT ... ON DUPLICATE KEY UPDATE thành CẬP NHẬT và nếu không có gì xảy ra thì chương trình sẽ thực hiện thao tác chèn. Vì hai lý do sau đây. 1. 99,9% hoạt động này là CẬP NHẬT. 2. Tôi thougt - không rõ ràng về giả mạo đó - có lẽ một INSERT xảy ra một khóa bảng.

Nhưng không có gì thay đổi. Sau đó tôi đã thử đoạn mã bằng khóa duy nhất. Không có gì thay đổi.

Sau đó, tôi đã có ý tưởng rằng có nhiều quy trình "ngủ" tại MySQL. Tôi điều này có được gây ra bởi rất dài chạy Gearman Scripts ?? Vì vậy, tôi đã thay đổi ví dụ Mã cho CẬP NHẬT như tôi đã đăng trước đây.

$this->db->beginTransaction(); 

     try { 
      for($i = 0; $i < count($asin); $i++) 
      { 
       if(isset($asin[$i]['price_total_end'])) 
       { 
        if(count($asin[$i]['price_total_end']) > 1) 
        { 
         // Es konnten Konkurrenten ausgemacht werden 
         if($asin[$i]['price_total_end'][0] > 0) 
         { 
          // Prüfe ob der eigene Preis der günstigste ist 
          if($asin[$i]['merchant_end'][0] == $merchantId) 
          { 
           // Ja der eigene Preis ist der günstigste, deshalb soll der nächste Preis der lowest sein. 
           $this->db->query("UPDATE userproducts SET lowest_price=".$asin[$i]['price_total_end'][1].", last_lowest_price_update='".date("Y-m-d H:i:s", time())."' WHERE product_id LIKE '".$asin[$i]['asin']."'"); 
          } else { 
           $this->db->query("UPDATE userproducts SET lowest_price=".$asin[$i]['price_total_end'][0].", last_lowest_price_update='".date("Y-m-d H:i:s", time())."' WHERE product_id LIKE '".$asin[$i]['asin']."'"); 
          } 
         } 
        } elseif(count($asin[$i]['price_total_end']) == 1) { 
         if($asin[$i]['price_total_end'][0] >= 0) 
         { 
          $this->db->query("UPDATE userproducts SET lowest_price=-1, last_lowest_price_update='".date("Y-m-d H:i:s", time())."' WHERE product_id LIKE '".$asin[$i]['asin']."'"); 
         } 
        } 
       } 
      } 
      $this->db->commit(); 
     } catch (Exception $e) { 
      $this->db->rollBack(); 
      echo $e->getMessage(); 
     } 
     **$this->db->closeConnection();** 

Nhưng không có gì thay đổi. Các kết nối vẫn ở 301 và Chủ đề tại 32. Tôi đã làm gì sai với Mã đó chưa.

Tôi thực sự không thể đối mặt với vấn đề.

Chúng tôi rất hoan nghênh ý tưởng và số lượng của bạn. Cảm ơn các bạn.

+0

Tôi không biết bất kỳ php nào nhưng tại sao tôi không thấy bất kỳ mysql_real_escape_string() nào? –

+1

Thường thì chúng tôi sử dụng PDO, - sửa lỗi cho tôi nếu sai - không cần thoát. Nhưng Zend beginnTransaction() chỉ có thể xử lý truy vấn db-> không phải là chèn mà tự xử lý thoát. Tôi chỉ chuyển nó cho phương thức query(). Đó là lý do tại sao tôi đã không trốn thoát. Nhưng thông tin chúng tôi thu thập được đến từ "lưu" tệp. Nhưng tất nhiên quyền của bạn. Chúng tôi thực sự nên làm điều này. –

Trả lời

1

thử đầu tiên lấy khóa chính cho tất cả các sản phẩm sử dụng:

SELECT primaryKey WHERE product_id LIKE '".$products[$i]['p_id']."'" 

và sau đó lặp qua các kết quả và cập nhật chúng bằng cách sử dụng PrimaryKey trong WHERE phần.

lặp lại điều đó cho tất cả các sản phẩm $ của bạn. và cam kết cuối cùng sau tất cả các lần lặp lại.

cảm giác ruột của tôi/kinh nghiệm trước đó cho biết rằng bạn sẽ có thể tránh được deadlocks theo cách này nhưng đáng buồn là tôi không thể đưa ra lời giải thích tại sao.

+0

Xin chào. Cảm ơn bạn đã gửi mã. Nhưng nếu tôi đúng thời gian chờ lỗi không phải là một loại bế tắc. Vì vậy, Im không chắc chắn nếu điều này thực sự giúp tôi. Nhưng chúng tôi cũng có trong bảng một số (2) uique Identifier, mà nên có cùng một perforamnce spped như chính, phải không? Nếu điều này đúng, tôi sẽ thử. Cảm ơn. –

+0

hãy thử và cho chúng tôi biết nó đã hoạt động như thế nào. – pQd

+0

Tôi đã thử, nhưng không có gì thay đổi. Chương trình đã không nhanh hơn hoặc là các lỗi đã biến mất. Nhưng dù gì cũng cảm ơn. –

Các vấn đề liên quan