ホームページ データベース mysql チュートリアル MySQL一个异常查询问题追查_MySQL

MySQL一个异常查询问题追查_MySQL

Jun 01, 2016 pm 01:14 PM
情報 ユーザー

问题

<code style="font-family: inherit; font-size: 14px; padding: 0px; color: inherit; background-color: transparent; white-space: pre-wrap; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; border: 0px;">线上碰到的问题:相同的语句,只是最后的limit行数不同。奇怪的是,limit 10 的性能比limit 100的语句还慢约10倍。隐藏用户表信息,语句及结果如下SELECTf1 , SUM(`f2`) `CNT` FROM TWHERE f1 IS NOT NULL AND f3 = '2014-05-12' GROUP BY f1 ORDER BY `CNT` DESC LIMIT 10;执行时间3 min 3.65 secSELECTf1 , SUM(`f2`) `CNT` FROM TWHERE f1 IS NOT NULL AND f3 = '2014-05-12' GROUP BY f1 ORDER BY `CNT` DESC LIMIT 100;执行时间1.24Sec.性能差距非常大!</code>
ログイン後にコピー

分析

<code style="font-family: inherit; font-size: 14px; padding: 0px; color: inherit; background-color: transparent; white-space: pre-wrap; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; border: 0px;">MySQL Tips:追查语句执行时最常用的方法,是通过explain来看语句的执行计划。 </code>
ログイン後にコピー
<code style="font-family: inherit; font-size: 14px; padding: 0px; color: inherit; background-color: transparent; white-space: pre-wrap; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; border: 0px;">更有冲击性的效果是通过缩小范围后,在这个数据下,limit 67和limit 68的执行计划相差很大。两个执行计划:LIMIT 67 id: 1select_type: SIMPLEtable: atype: rangepossible_keys: A,B,Ckey: Bkey_len: 387ref: NULLrows: 2555192Extra: Using where; Using temporary; Using filesort1 row in set (0.00 sec) LIMIT 68id: 1select_type: SIMPLEtable: atype: refpossible_keys: A,B,Ckey: Akey_len: 3ref: constrows: 67586Extra: Using where; Using temporary; Using filesort1 row in set (0.00 sec)可以看到,两个语句的执行计划不同:使用的索引不同。</code>
ログイン後にコピー
<code style="font-family: inherit; font-size: 14px; padding: 0px; color: inherit; background-color: transparent; white-space: pre-wrap; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; border: 0px;">MySQL Tips:explain的结果中,key表示最终使用的索引,rows表示使用这个索引需要扫描的行数,这是个估计值。表中 索引A定义为 (f3, f4, f1, f2, f5); 索引B定义为(f1, f2, f3);</code>
ログイン後にコピー

一个确认

<code style="font-family: inherit; font-size: 14px; padding: 0px; color: inherit; background-color: transparent; white-space: pre-wrap; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; border: 0px;">虽然rows是估计值,但是指导索引使用的依据。既然limit 68能达到rows 67586, 说明在第一个语句优化器可选结果中,也应该有此值,为什么不会选择索引A?先确认一下我们上面的这个结论。</code>
ログイン後にコピー
<code style="font-family: inherit; font-size: 14px; padding: 0px; color: inherit; background-color: transparent; white-space: pre-wrap; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; border: 0px;">MySQL Tips:MySQL语法中能够用force index 来强行要求优化器使用某一个索引。</code>
ログイン後にコピー

Explain SELECT f1 , SUM(f2CNT FROM t force index(A) WHERE f1 IS NOT NULL AND f3 = ‘2014-05-12’ GROUP BY P ORDER BY CNT DESC LIMIT 67/G

id: 1 
select_type: SIMPLE 
table: a 
type: ref 
possible_keys:A 
key: A 
key_len: 3 
ref: const 
rows: 67586 
Extra: Using where; Using temporary; Using filesort 
1 row in set (0.00 sec)

<code style="font-family: inherit; font-size: 14px; padding: 0px; color: inherit; background-color: transparent; white-space: pre-wrap; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; border: 0px;">顺便说明,由于我们指定了force index,因此优化器不会考虑其他索引,possible_keys里只会显示A。我们关注的是rows:67586。这说明在limit 67语句里,使用索引A也能够减少行扫描。</code>
ログイン後にコピー
<code style="font-family: inherit; font-size: 14px; padding: 0px; color: inherit; background-color: transparent; white-space: pre-wrap; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; border: 0px;">MySQL Tips:MySQL优化器会对possiable_key中的每个可能索引都计算查询代价,选择最小代价的查询计划。</code>
ログイン後にコピー
<code style="font-family: inherit; font-size: 14px; padding: 0px; color: inherit; background-color: transparent; white-space: pre-wrap; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; border: 0px;">至此我们大概可以猜测,这个应该是MySQL实现上的bug:没有选择合适的索引,导致使用了明显错误的执行计划。</code>
ログイン後にコピー
<code style="font-family: inherit; font-size: 14px; padding: 0px; color: inherit; background-color: transparent; white-space: pre-wrap; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; border: 0px;">MySQL Tips:MySQL的优化器执行期间需要依赖于表的统计信息,而统计信息是估算值,因此有可能导致得到的执行计划非最优。</code>
ログイン後にコピー
<code style="font-family: inherit; font-size: 14px; padding: 0px; color: inherit; background-color: transparent; white-space: pre-wrap; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; border: 0px;">但要说明的是,上述Tip是客观情况造成(可接受),但本例却是例外,因此优化器实际上可以拿到能够作出选择正确结果的数据(rows值),但是最终选择错误。</code>
ログイン後にコピー

原因分析

<code style="font-family: inherit; font-size: 14px; padding: 0px; color: inherit; background-color: transparent; white-space: pre-wrap; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; border: 0px;">MySQL优化器是按照查询代价的估算值,来确定要使用的索引。计算这个估算值的过程,基本是按照“估计需要扫描的行数”来确定的。</code>
ログイン後にコピー
<code style="font-family: inherit; font-size: 14px; padding: 0px; color: inherit; background-color: transparent; white-space: pre-wrap; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; border: 0px;">MySQL Tips:MySQL在目前集团主流使用的5.1和5.5版本中只能使用前缀索引。</code>
ログイン後にコピー

因此,使用索引A只能用上字段f3,使用索引B只能用上字段f1。Rows即为使用了索引查到上下界,之后需要扫描的数据行数(估算值)。

<code style="font-family: inherit; font-size: 14px; padding: 0px; color: inherit; background-color: transparent; white-space: pre-wrap; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; border: 0px;">上述的语句需要用到group和order by,因此执行计划中都有Using temporary; Using filesort。流程上按顺序先计算使用索引A的查询代价。之后依次计算其他possitabe_key的查询代价。由于过程中需要排序,在得到一个暂定结果后,需要判断是否有代价更低的排序方式(test_if_cheaper_ordering)。与之前的大同小异,也是依靠估计扫描行数来计算代价。在这个逻辑的实现过程中,存在一个bug:在估计当前索引的区分度的时候,没有考虑到前缀索引。即:假设表中有50w行数据,索引B(f1,f2,f3),则计算索引区分度时,需要根据能够用上的前缀部分来确定。比如f1有1000个不同的值,则平均每个key值上的记录数为500.如(f1,f2)有10000个同的值,则平均每个组合key上的记录数为50,若(f1,f2,f3)有50w个不同的值,则平均每个组合key上的记录数为1。</code>
ログイン後にコピー
<code style="font-family: inherit; font-size: 14px; padding: 0px; color: inherit; background-color: transparent; white-space: pre-wrap; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; border: 0px;">MySQL Tips:每个key上的记录数越少,说明使用该索引查询时效率最高。对应于show index from tbl 输出结果中的Cardinality值越大。</code>
ログイン後にコピー

在这个case下,索引A只能使用f1做前缀索引,但是在计算单key上的行平均值时用的是(f1,f2,f3),这就导致估算用索引B估算的时候,得到的代价偏小。导致误选。

回到问题本身

<code style="font-family: inherit; font-size: 14px; padding: 0px; color: inherit; background-color: transparent; white-space: pre-wrap; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; border: 0px;">1、为什么limit值大的时候反而选对了呢?</code>这是因为在计算B的查询代价时,查询需要返回的行数limit_rows也参与乘积,若limit值较大,则计算出来的B的代价就会更大,反而会由于代价。值超过A,而导致优化器最终选择A。
ログイン後にコピー
<code style="font-family: inherit; font-size: 14px; padding: 0px; color: inherit; background-color: transparent; white-space: pre-wrap; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; border: 0px;">2、这个表有50w行数就,为什么limit相差为就差别这么大?这与语句本身有关。这个语句中有group by,这就意味着每多limit一个值,实际上需要扫描更多的行N。 这里N为“表的总行数”/“表中不同的f2值”。也就是说这个语句使得这个bug有放大作用。</code>
ログイン後にコピー

解决方案

<code style="font-family: inherit; font-size: 14px; padding: 0px; color: inherit; background-color: transparent; white-space: pre-wrap; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; border: 0px;">分析清楚后解决方法就比较简单了,修改代码逻辑,在执行test_if_cheaper_ordering过程中,改用字段f1的区分度来计算即可。</code>
ログイン後にコピー
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Xiaohonshu アカウントを使用してユーザーを見つけるにはどうすればよいですか?私の携帯電話番号を見つけることはできますか? Xiaohonshu アカウントを使用してユーザーを見つけるにはどうすればよいですか?私の携帯電話番号を見つけることはできますか? Mar 22, 2024 am 08:40 AM

ソーシャルメディアの急速な発展に伴い、Xiaohongshuは最も人気のあるソーシャルプラットフォームの1つになりました。ユーザーは、Xiaohongshu アカウントを作成して自分の個人情報を示し、他のユーザーと通信し、対話することができます。ユーザーの小紅樹番号を見つける必要がある場合は、次の簡単な手順に従ってください。 1. Xiaohonshu アカウントを使用してユーザーを見つけるにはどうすればよいですか? 1. 小紅書アプリを開き、右下隅の「検出」ボタンをクリックして、「メモ」オプションを選択します。 2. ノート一覧で、探したいユーザーが投稿したノートを見つけます。クリックしてノートの詳細ページに入ります。 3. ノートの詳細ページで、ユーザーのアバターの下にある「フォロー」ボタンをクリックして、ユーザーの個人ホームページに入ります。 4. ユーザーの個人ホームページの右上隅にある三点ボタンをクリックし、「個人情報」を選択します。

Windows 11 でローカル ユーザーとグループが見つからない: 追加する方法 Windows 11 でローカル ユーザーとグループが見つからない: 追加する方法 Sep 22, 2023 am 08:41 AM

ローカル ユーザーとグループ ユーティリティはコンピュータの管理に組み込まれており、コンソールからまたは独立してアクセスできます。ただし、一部のユーザーは、Windows 11 でローカル ユーザーとグループが見つからないことに気づきます。これにアクセスできる一部のユーザーに対して、このメッセージは、このスナップインがこのバージョンの Windows 10 では動作しない可能性があることを示唆しています。このコンピュータのユーザー アカウントを管理するには、コントロール パネルのユーザー アカウント ツールを使用します。この問題は Windows 10 の以前のバージョンでも報告されており、通常はユーザー側の問題や見落としが原因で発生します。 Windows 11 でローカル ユーザーとグループが表示されないのはなぜですか? Windows Home エディションを実行しています。ローカル ユーザーとグループは、Professional エディション以降で使用できます。活動

スーパーユーザーとして Ubuntu にログインします スーパーユーザーとして Ubuntu にログインします Mar 20, 2024 am 10:55 AM

Ubuntu システムでは、通常、root ユーザーは無効になっています。 root ユーザーをアクティブにするには、passwd コマンドを使用してパスワードを設定し、su-コマンドを使用して root としてログインします。 root ユーザーは、無制限のシステム管理権限を持つユーザーです。彼は、ファイルへのアクセスと変更、ユーザー管理、ソフトウェアのインストールと削除、およびシステム構成の変更を行う権限を持っています。 root ユーザーと一般ユーザーの間には明らかな違いがあり、root ユーザーはシステム内で最高の権限とより広範な制御権限を持ちます。 root ユーザーは、一般のユーザーでは実行できない重要なシステム コマンドを実行したり、システム ファイルを編集したりできます。このガイドでは、Ubuntu の root ユーザー、root としてログインする方法、および通常のユーザーとの違いについて説明します。知らせ

Windows 11 ガイドの探索: 古いハード ドライブ上のユーザー フォルダーにアクセスする方法 Windows 11 ガイドの探索: 古いハード ドライブ上のユーザー フォルダーにアクセスする方法 Sep 27, 2023 am 10:17 AM

特定のフォルダーは権限の関係で常にアクセスできるわけではありません。今日のガイドでは、Windows 11 で古いハード ドライブ上のユーザー フォルダーにアクセスする方法を説明します。このプロセスは簡単ですが、ドライブのサイズによっては、しばらく時間がかかり、場合によっては数時間もかかる場合があるため、特に忍耐強く、このガイドの指示に厳密に従ってください。古いハードドライブ上のユーザーフォルダーにアクセスできないのはなぜですか?ユーザー フォルダーは別のコンピューターによって所有されているため、変更できません。このフォルダーには所有権以外の権限がありません。古いハードドライブ上のユーザーファイルを開くにはどうすればよいですか? 1. フォルダーの所有権を取得し、アクセス許可を変更します。 古いユーザー ディレクトリを見つけて右クリックし、[プロパティ] を選択します。 「An」に移動します

チュートリアル: Ubuntu システムで通常のユーザー アカウントを削除する方法は? チュートリアル: Ubuntu システムで通常のユーザー アカウントを削除する方法は? Jan 02, 2024 pm 12:34 PM

Ubuntu システムに多くのユーザーが追加されました。使用しなくなったユーザーを削除したいのですが、どうすればよいですか?以下の詳細なチュートリアルを見てみましょう。 1. ターミナルのコマンドラインを開き、userdel コマンドを使用して、指定したユーザーを削除します。下図に示すように、必ず sudo 権限コマンドを追加してください。 2. 削除するときは、必ず管理者ディレクトリにいることを確認してください。一般ユーザー以下の図に示すように、この権限がありません。 3. 削除コマンドを実行した後、本当に削除されたかどうかをどのように判断しますか?次に、下の図に示すように、cat コマンドを使用して passwd ファイルを開きます。 4. 次の図に示すように、削除されたユーザー情報が passwd ファイル内になくなっていることがわかり、ユーザーが削除されたことがわかります。 5. 次に、ホームファイルを入力します

sudo とは何ですか?なぜ重要ですか? sudo とは何ですか?なぜ重要ですか? Feb 21, 2024 pm 07:01 PM

sudo (スーパーユーザー実行) は、一般ユーザーが root 権限で特定のコマンドを実行できるようにする、Linux および Unix システムの重要なコマンドです。 sudo の機能は主に次の側面に反映されています。 権限制御の提供: sudo は、ユーザーにスーパーユーザー権限を一時的に取得することを許可することで、システム リソースと機密性の高い操作を厳密に制御します。一般のユーザーは、必要な場合にのみ sudo を介して一時的な権限を取得できるため、常にスーパーユーザーとしてログインする必要はありません。セキュリティの向上: sudo を使用すると、日常的な操作中に root アカウントの使用を回避できます。すべての操作に root アカウントを使用すると、誤った操作や不注意な操作には完全な権限が与えられるため、予期しないシステムの損傷につながる可能性があります。そして

Windows 11 KB5031455 のインストールに失敗し、一部のユーザーに他の問題が発生する Windows 11 KB5031455 のインストールに失敗し、一部のユーザーに他の問題が発生する Nov 01, 2023 am 08:17 AM

Microsoft は、Windows 503145511H22 以降のオプションの更新プログラムとして KB2 の一般公開を開始しました。これは、サポートされている領域での Windows Copilot、スタート メニューの項目のプレビュー サポート、タスク バーのグループ解除などを含む、Windows 11 Moment 4 の機能をデフォルトで有効にする最初の更新プログラムです。さらに、メモリ リークを引き起こす潜在的なパフォーマンスの問題など、Windows 11 のいくつかのバグも修正されています。しかし皮肉なことに、2023 年 9 月のオプションのアップデートは、アップデートをインストールしようとしているユーザーにとっても、すでにインストールしているユーザーにとっても大惨事となるでしょう。多くのユーザーはこの Wi をインストールしないでしょう

Linuxシステムにおけるユーザーパスワード保存メカニズムの分析 Linuxシステムにおけるユーザーパスワード保存メカニズムの分析 Mar 20, 2024 pm 04:27 PM

Linux システムにおけるユーザー パスワードの保存メカニズムの分析 Linux システムでは、ユーザー パスワードの保存は非常に重要なセキュリティ メカニズムの 1 つです。この記事では、パスワードの暗号化された保存、パスワード検証プロセス、ユーザー パスワードを安全に管理する方法など、Linux システムにおけるユーザー パスワードの保存メカニズムを分析します。同時に、具体的なコード例を使用して、パスワード保存の実際の操作プロセスを示します。 1. パスワードの暗号化された保管 Linux システムでは、ユーザーのパスワードは平文でシステムに保管されるのではなく、暗号化されて保管されます。 L

See all articles