2016-07-21 38 views
6

私たちはmysql 5.7にアップグレードして、5.6のカウンタ部分よりもはるかに遅いことを発見しました。どちらもほぼ同じ設定ですが、5.6ではほとんどのsqlsがミリ秒単位で実行されますが、もう一方のバージョンは中間の複合型SQLの場合には約1秒以上かかります。mysql 5.7はmedium sqlのmysql 5.6よりもはるかに遅い

-- Getting most recent users that are email-verified and not banned 

SELECT 
    `u`.* 
FROM 
    `user` AS `u` 
INNER JOIN `user` user_table_alias ON user_table_alias.`id` = `u`.`id` 
LEFT JOIN `user_suspend` user_suspend_table_alias ON user_suspend_table_alias.`userId` = `user_table_alias`.`id` 
WHERE 
    (
     `user_suspend_table_alias`.`id` IS NULL 
    ) 
AND 
    `user_table_alias`.`emailVerify` = 1 

ORDER BY 
    `u`.`joinStamp` DESC 
LIMIT 1, 18 

両方のテーブルは非常にシンプルであり、インデックス化:

-- ---------------------------- 
-- Table structure for user 
-- ---------------------------- 
DROP TABLE IF EXISTS `user`; 
CREATE TABLE `user` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `email` varchar(128) NOT NULL DEFAULT '', 
    `username` varchar(32) NOT NULL DEFAULT '', 
    `password` varchar(64) NOT NULL DEFAULT '', 
    `joinStamp` int(11) NOT NULL DEFAULT '0', 
    `activityStamp` int(11) NOT NULL DEFAULT '0', 
    `accountType` varchar(32) NOT NULL DEFAULT '', 
    `emailVerify` tinyint(2) NOT NULL DEFAULT '0', 
    `joinIp` int(11) unsigned NOT NULL, 
    `locationId` int(11) DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `email` (`email`), 
    UNIQUE KEY `username` (`username`), 
    KEY `accountType` (`accountType`), 
    KEY `joinStamp` (`joinStamp`), 
    KEY `activityStamp` (`activityStamp`) 
) ENGINE=MyISAM AUTO_INCREMENT=89747 DEFAULT CHARSET=utf8 COMMENT='utf8_general_ci'; 

-- ---------------------------- 
-- Table structure for user_suspend 
-- ---------------------------- 
DROP TABLE IF EXISTS `user_suspend`; 
CREATE TABLE `user_suspend` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `userId` int(11) DEFAULT NULL, 
    `timestamp` int(11) DEFAULT NULL, 
    `message` text NOT NULL, 
    `expire` int(11) DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `userId` (`userId`) 
) ENGINE=MyISAM AUTO_INCREMENT=513 DEFAULT CHARSET=utf8; 

表は、それぞれの周り100Kと1Kの行を持っています。

  1. ORDER BYを削除すると、実行時間が約1.2秒から0.0015秒に短縮されました。
  2. SQLはMySQLの5.7

注によってキャッシュされていない:私たちはキャッシュクエリを持っている:

のSHOW STATUS LIKE 'Qcacheの%'

Qcache_free_blocks 19408 
Qcache_free_memory 61782816 
Qcache_hits 31437169 
Qcache_inserts 2406719 
Qcache_lowmem_prunes 133483 
Qcache_not_cached 43555 
Qcache_queries_in_cache 41691 
Qcache_total_blocks 103951 

私は多くの問題をGoogleで検索して見つけました5.7で報告されましたが、なぜこのSQL上でこの奇妙な振る舞いをしていませんか(まだ5.7ではずっと遅く走っている他のsqlsもたくさんあります)。

id select_type  table    partitions type  possible_keys key   key_len  ref rows filtered Extra 
1 SIMPLE  user_table_alias  NULL  ALL   PRIMARY  NULL  NULL  NULL 104801 10.00 Using where; Usingtemporary; Usingfilesort 
1 SIMPLE  u    NULL  eq_ref  PRIMARY  PRIMARY  4  knn.base_user_table_alias.id 1 100.00 NULL 
1 SIMPLE  user_suspend_table_alias NULL  ref   userId userId   5  knn.base_user_table_alias.id 1 10.00 Using where; 
+0

スピードが必要な場合は、どうしてMyISAMを使用しますか? – Mjh

+1

あなたはEXPLAINを投稿できますか? –

+0

"profile"を使用して、SQLの時間コストを分析します。各段階で時間コストを示すことができます。 –

答えて

2

user_table_alias ON INNER JOIN user user_table_alias:ここ

はネビルKによって示唆、EXPLAINです。 id = uidは役に立たないようです。それは自分自身と結合するだけで、そのテクニックは残りのクエリでは使用されません。

emailVerifyにはインデックスがありません。 EXPLAINの最初の行で示されます。 (インデックスが使用されていない意味「どこ使用して」)完全なテーブルが何最近のユーザーを区切る前に見なければならないので、このクエリは、テーブルのサイズとうまくスケールしない

です。だから、おそらくmyisamによって使用されるいくつかの内部バッファがオーバーフローしています。 これは、「一時的な使用」を意味します。 filesortを使用すると、order byは非常に大きいので、パフォーマンスに悪い一時ファイルを使用します。

+0

実際には、私は 'user_table_alias'を変更しました.'emailVerify' = 1 =>' u'.emailVerify' = 1そしてもう一度すばやくです。 Dunnoはなぜmysql5.6で両方とも高速化しています –

0

Ok、Thanks to NevilleK on Explain。

私はちょうどONLYこのSQLを修正する方法を考え出し:

user_table_alias.emailVerify = 1 

u.emailVerify = 1 

に知らんなぜ、しかしmysql5.6で、両方をmillisecsで実行されています。

Iは、自己結合が冗長に見えるMySQLの後方改善のおかげ

1

、私は(他の開発者からの)すべてのSQLを検討する必要がありますね。

次のように私はあなたが再書き込みできるクエリと思う:

SELECT 
    `u`.* 
FROM 
    `user` AS `u` 
LEFT JOIN `user_suspend` user_suspend_table_alias ON user_suspend_table_alias.`userId` = `u`.`id` 
WHERE `user_suspend_table_alias`.`id` IS NULL 
AND  `u`.`emailVerify` = 1 
ORDER BY 
    `u`.`joinStamp` DESC 
LIMIT 1, 18 

私は「emailVerify」を想定し、値(0と1)のほんの一握りを持つ列であるため、インデックスを作成するべきではありません。私はまた、 "joinStamp"はある種のタイムスタンプであると仮定します(データ型は整数です)。それが本当であれば、これをさらにスピードアップするための索引を作成することができます。

create index id_joinstamp on user (id, joinstamp) 
+0

あなたのクエリはもっと​​よく見えますが、私たちの "join-to-user-tables"はちょっと再利用可能なコードです。つまり、 "product"、 "post"、 "transaction" ...などの他の多くのテーブルも "user-user_suspend"に結合されています。コードは他のチームのものですが、私はあまり不平を言っていません。私はあなたのアドバイスを適用しようとします –

関連する問題