web-dev-qa-db-ja.com

MySQL UPDATEクエリが「データの送信」状態でスタック

プロセスが「データの送信中」の状態でスタックしているため、UPDATEクエリを正常に実行できません。

これは 「データの送信」状態に関する同様の質問 とは異なると思います。これは、MySQL のドキュメントであるUPDATEクエリ中に発生するためです 起こらないと信じるように私を導きます。 (?)

関連する2つの表を次に示します。

CREATE TABLE `CustomerVisits` (
  `ID` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `OrderID` INT(10) UNSIGNED NOT NULL,
  `MerchantID` INT(10) UNSIGNED NOT NULL,
  `LocationID` INT(10) UNSIGNED NOT NULL,
  `CTime` INT(10) UNSIGNED NOT NULL,
  `CustomerID` INT(10) UNSIGNED NULL DEFAULT NULL,
  `SinceLastVisit` INT(10) UNSIGNED NULL DEFAULT NULL,
  PRIMARY KEY (`ID`),
  INDEX `CTime` (`CTime`) USING BTREE,
  INDEX `LocationID_OrderID_CTime` (`LocationID`, `OrderID`, `CTime`) USING BTREE,
  INDEX `OrderID` (`OrderID`),
  INDEX `CustomerID` (`CustomerID`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB;

CREATE TABLE `VisitDiffTimes` (
  `DiffTime` DOUBLE NULL DEFAULT NULL,
  `OrderID` INT(10) UNSIGNED NOT NULL,
  `MerchantID` INT(10) UNSIGNED NOT NULL DEFAULT '0',
  `CustomerID` INT(10) UNSIGNED NOT NULL DEFAULT '0',
  `CTime` INT(10) UNSIGNED NULL DEFAULT NULL,
  PRIMARY KEY (`MerchantID`, `OrderID`, `CustomerID`) USING HASH,
  INDEX `DiffTime` (`DiffTime`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB;

CustomerVisitsには1200万行あり、VisitDiffTimesには400万行あります。

CustomerVisits.SinceLastVisit列は現在すべてNULLです-次のクエリを入力します。

UPDATE CustomerVisits V
  JOIN VisitDiffTimes D
    ON V.OrderID = D.OrderID AND V.CustomerID = D.CustomerID
   SET V.SinceLastVisit = D.DiffTime

このクエリのEXPLAINの出力は次のとおりです。

id  select_type  table  type   possible_keys       key       key_len  ref        rows     Extra
1   SIMPLE       D      index  NULL                DiffTime  9        NULL       4065127  Using index
1   SIMPLE       V      ref    OrderID,CustomerID  OrderID   4        D.OrderID  1        Using where

この操作を高速化できるクエリまたはテーブル定義に問題がありますか?


更新

以下にRolandoMySQLDBAの提案を実装しましたが、残念ながら、クエリはまだ何度も実行されています。

SHOW ENGINE InnoDB STATUSの結果を以下に示します。エンジンが0.00 updates/sを報告しているのを確認したので、このクエリが妥当な時間内に完了に向かわないのではないかと心配しています。

=====================================
2015-09-24 15:55:40 7f9d02217700 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 7 seconds
-----------------
BACKGROUND THREAD
-----------------
srv_master_thread loops: 65705 srv_active, 0 srv_shutdown, 46262 srv_idle
srv_master_thread log flush and writes: 111963
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 2282726
OS WAIT ARRAY INFO: signal count 3647755
Mutex spin waits 3344497, rounds 28268630, OS waits 400079
RW-shared spins 2898160, rounds 69659833, OS waits 1747791
RW-excl spins 365077, rounds 10516470, OS waits 86454
Spin rounds per wait: 8.45 mutex, 24.04 RW-shared, 28.81 RW-excl
------------
TRANSACTIONS
------------
Trx id counter 26361458
Purge done for trx's n:o < 26361455 undo n:o < 0 state: running but idle
History list length 1926
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0, not started
MySQL thread id 1595, OS thread handle 0x7f9d02217700, query id 70163629 (IP Address) (Username) init
SHOW ENGINE InnoDB STATUS
---TRANSACTION 26361457, ACTIVE 2764 sec fetching rows
mysql tables in use 2, locked 2
50350 lock struct(s), heap size 4617768, 181942 row lock(s)
MySQL thread id 1579, OS thread handle 0x7f9d02299700, query id 70163374 (IP Address) (Username) Sending data
UPDATE SaleOrderPayment P
  JOIN SaleOrderPayment_Diff_Merchant T
    ON P.OrderID = T.OrderID AND P.CustomerID = T.CustomerID
   SET P.SinceLastVisitMerchant = T.DiffTime
--------
FILE I/O
--------
I/O thread 0 state: waiting for i/o request (insert buffer thread)
I/O thread 1 state: waiting for i/o request (log thread)
I/O thread 2 state: waiting for i/o request (read thread)
I/O thread 3 state: waiting for i/o request (read thread)
I/O thread 4 state: waiting for i/o request (read thread)
I/O thread 5 state: waiting for i/o request (read thread)
I/O thread 6 state: waiting for i/o request (write thread)
I/O thread 7 state: waiting for i/o request (write thread)
I/O thread 8 state: waiting for i/o request (write thread)
I/O thread 9 state: waiting for i/o request (write thread)
Pending normal aio reads: 0 [0, 0, 0, 0] , aio writes: 0 [0, 0, 0, 0] ,
 ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
Pending flushes (fsync) log: 0; buffer pool: 0
137002174 OS file reads, 20383973 OS file writes, 844094 OS fsyncs
18277.25 reads/s, 16771 avg bytes/read, 0.00 writes/s, 0.00 fsyncs/s
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 2723, seg size 2725, 5175728 merges
merged operations:
 insert 13665166, delete mark 8438509, delete 8253
discarded operations:
 insert 0, delete mark 0, delete 0
Hash table size 415109, node heap has 71 buffer(s)
443.79 hash searches/s, 32426.94 non-hash searches/s
---
LOG
---
Log sequence number 125059941125
Log flushed up to   125059941125
Pages flushed up to 125059941125
Last checkpoint at  125059941125
0 pending log writes, 0 pending chkp writes
11664686 log i/o's done, 0.00 log i/o's/second
----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 214630400; in additional pool allocated 0
Dictionary memory allocated 172905
Buffer pool size   12799
Free buffers       0
Database pages     12447
Old database pages 4602
Modified db pages  0
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 1352321, not young 1300347433
0.00 youngs/s, 147255.82 non-youngs/s
Pages read 144210003, created 530043, written 12368276
18709.33 reads/s, 0.00 creates/s, 0.00 writes/s
Buffer pool hit rate 876 / 1000, young-making rate 0 / 1000 not 983 / 1000
Pages read ahead 438.79/s, evicted without access 66.99/s, Random read ahead 0.00/s
LRU len: 12447, unzip_LRU len: 0
I/O sum[915059]:cur[17449], unzip sum[0]:cur[0]
--------------
ROW OPERATIONS
--------------
0 queries inside InnoDB, 0 queries in queue
0 read views open inside InnoDB
Main thread process no. 24315, id 140312316348160, state: sleeping
Number of rows inserted 36456765, updated 13112249, deleted 16214487, read 688045738
0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 32871.02 reads/s
----------------------------
END OF INNODB MONITOR OUTPUT
============================

アップデート2

以下は、RolandoMySQLDBAの以下の提案に従って更新されたEXPLAIN出力です。

id  select_type  table  type   possible_keys                  key         key_le   ref           rows     Extra
1   SIMPLE       D      index  PRIMARY                        DiffTime    9        NULL          4044212  Using index
1   SIMPLE       V      ref    CustomerID,OrderID_CustomerID  CustomerID  5        D.CustomerID  1        Using where

アップデート3

RolandoMySQLDBAを実装しました 提案4 未満;更新されたEXPLAIN出力は次のとおりです。

id  select_type  table  type   possible_keys                          key                 key_len  ref                     rows     Extra
1   SIMPLE       D      index  PRIMARY                                DiffTime            9        NULL                    4044212  Using index
1   SIMPLE       V      ref    OrderID_CustomerID,CustomerID_OrderID  OrderID_CustomerID  9        D.OrderID,D.CustomerID  1        NULL
1
djeffery

問題

EXPLAINプランでは、select_typeSIMPLEです。

これは、フルインデックススキャンVisitDiffTimesCustomerVisitsの範囲スキャンです。

提案#1

VisitDiffTimesの主キーの列を並べ替える必要があります

ALTER TABLE VisitDiffTimes DROP PRIMARY KEY;
ALTER TABLE VisitDiffTimes ADD PRIMARY KEY (`OrderID`, `CustomerID`, `MerchantID`);

これにより、VisitDiffTimesの完全スキャンが削除されます

提案#2(オプション)

CustomerVisitsの2つの列に複合インデックスを作成します

ALTER TABLE CustomerVisits
    DROP INDEX OrderID,
    ADD INDEX OrderID_CustomerID_ndx (OrderID,CustomerID)
;

JOINはよりクリーンになる可能性があります

提案#3(オプション)

Join_buffer_sizeを16Mに設定します

これをmy.cnfに追加

[mysqld]
join_buffer_size = 16M

再起動する必要はありません。 root@localhostとしてログインして実行するだけです

mysql> SET GLOBAL join_buffer_size = 16 * 1024 * 1024;

試してみる !!!

提案#4(オプション)

列を含む別のインデックス(CustomerID,OrderID)

ALTER TABLE CustomerVisits
    DROP INDEX CustomerID,
    ADD INDEX CustomerID_OrderID_ndx (CustomerID,OrderID)
;
2
RolandoMySQLDBA