Heim Datenbank MySQL-Tutorial 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>
Nach dem Login kopieren

分析

<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>
Nach dem Login kopieren
<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>
Nach dem Login kopieren
<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>
Nach dem Login kopieren

一个确认

<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>
Nach dem Login kopieren
<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>
Nach dem Login kopieren

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>
Nach dem Login kopieren
<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>
Nach dem Login kopieren
<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>
Nach dem Login kopieren
<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>
Nach dem Login kopieren
<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>
Nach dem Login kopieren

原因分析

<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>
Nach dem Login kopieren
<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>
Nach dem Login kopieren

因此,使用索引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>
Nach dem Login kopieren
<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>
Nach dem Login kopieren

在这个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。
Nach dem Login kopieren
<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>
Nach dem Login kopieren

解决方案

<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>
Nach dem Login kopieren
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

AI Hentai Generator

AI Hentai Generator

Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

R.E.P.O. Energiekristalle erklärten und was sie tun (gelber Kristall)
2 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Beste grafische Einstellungen
2 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. So reparieren Sie Audio, wenn Sie niemanden hören können
2 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Wie verwende ich das Xiaohongshu-Konto, um Benutzer zu finden? Kann ich meine Handynummer finden? Wie verwende ich das Xiaohongshu-Konto, um Benutzer zu finden? Kann ich meine Handynummer finden? Mar 22, 2024 am 08:40 AM

Mit der rasanten Entwicklung der sozialen Medien hat sich Xiaohongshu zu einer der beliebtesten sozialen Plattformen entwickelt. Benutzer können ein Xiaohongshu-Konto erstellen, um ihre persönliche Identität zu zeigen und mit anderen Benutzern zu kommunizieren und zu interagieren. Wenn Sie die Xiaohongshu-Nummer eines Benutzers finden müssen, können Sie diese einfachen Schritte befolgen. 1. Wie verwende ich das Xiaohongshu-Konto, um Benutzer zu finden? 1. Öffnen Sie die Xiaohongshu-App, klicken Sie auf die Schaltfläche „Entdecken“ in der unteren rechten Ecke und wählen Sie dann die Option „Notizen“. 2. Suchen Sie in der Notizenliste nach der Notiz, die von dem Benutzer gepostet wurde, den Sie suchen möchten. Klicken Sie hier, um die Seite mit den Notizdetails aufzurufen. 3. Klicken Sie auf der Seite mit den Notizdetails auf die Schaltfläche „Folgen“ unter dem Avatar des Benutzers, um zur persönlichen Homepage des Benutzers zu gelangen. 4. Klicken Sie in der oberen rechten Ecke der persönlichen Homepage des Benutzers auf die Schaltfläche mit den drei Punkten und wählen Sie „Persönliche Informationen“.

Lokale Benutzer und Gruppen fehlen unter Windows 11: So fügen Sie sie hinzu Lokale Benutzer und Gruppen fehlen unter Windows 11: So fügen Sie sie hinzu Sep 22, 2023 am 08:41 AM

Das Dienstprogramm „Lokale Benutzer und Gruppen“ ist in die Computerverwaltung integriert und kann über die Konsole oder unabhängig davon aufgerufen werden. Einige Benutzer stellen jedoch fest, dass in Windows 11 lokale Benutzer und Gruppen fehlen. Für einige Personen, die Zugriff darauf haben, deutet die Meldung darauf hin, dass dieses Snap-In möglicherweise nicht mit dieser Version von Windows 10 funktioniert. Um Benutzerkonten für diesen Computer zu verwalten, verwenden Sie das Benutzerkonten-Tool in der Systemsteuerung. Das Problem wurde in früheren Versionen von Windows 10 gemeldet und wird normalerweise durch Probleme oder Versäumnisse auf Seiten des Benutzers verursacht. Warum fehlen lokale Benutzer und Gruppen in Windows 11? Sie verwenden die Windows Home Edition. Lokale Benutzer und Gruppen sind in der Professional Edition und höher verfügbar. Aktivität

Melden Sie sich als Superuser bei Ubuntu an Melden Sie sich als Superuser bei Ubuntu an Mar 20, 2024 am 10:55 AM

In Ubuntu-Systemen ist der Root-Benutzer normalerweise deaktiviert. Um den Root-Benutzer zu aktivieren, können Sie mit dem Befehl passwd ein Passwort festlegen und sich dann mit dem Befehl su- als Root anmelden. Der Root-Benutzer ist ein Benutzer mit uneingeschränkten Systemadministratorrechten. Er verfügt über Berechtigungen zum Zugriff auf und zum Ändern von Dateien, zur Benutzerverwaltung, zum Installieren und Entfernen von Software sowie zum Ändern der Systemkonfiguration. Es gibt offensichtliche Unterschiede zwischen dem Root-Benutzer und normalen Benutzern. Der Root-Benutzer verfügt über die höchste Autorität und umfassendere Kontrollrechte im System. Der Root-Benutzer kann wichtige Systembefehle ausführen und Systemdateien bearbeiten, was normale Benutzer nicht können. In dieser Anleitung werde ich den Ubuntu-Root-Benutzer untersuchen, wie man sich als Root anmeldet und wie er sich von einem normalen Benutzer unterscheidet. Beachten

Entdecken Sie den Windows 11-Leitfaden: So greifen Sie auf Benutzerordner auf Ihrer alten Festplatte zu Entdecken Sie den Windows 11-Leitfaden: So greifen Sie auf Benutzerordner auf Ihrer alten Festplatte zu Sep 27, 2023 am 10:17 AM

Auf einige Ordner kann aufgrund von Berechtigungen nicht immer zugegriffen werden. In der heutigen Anleitung zeigen wir Ihnen, wie Sie unter Windows 11 auf Benutzerordner auf Ihrer alten Festplatte zugreifen. Der Vorgang ist einfach, kann aber je nach Größe des Laufwerks eine Weile dauern, manchmal sogar Stunden. Seien Sie also besonders geduldig und befolgen Sie die Anweisungen in dieser Anleitung genau. Warum kann ich auf meiner alten Festplatte nicht auf meine Benutzerordner zugreifen? Benutzerordner gehören einem anderen Computer und können daher nicht geändert werden. Sie haben für diesen Ordner keine anderen Berechtigungen als den Besitz. Wie öffne ich Benutzerdateien auf einer alten Festplatte? 1. Übernehmen Sie den Besitz des Ordners und ändern Sie die Berechtigungen. Suchen Sie das alte Benutzerverzeichnis, klicken Sie mit der rechten Maustaste darauf und wählen Sie „Eigenschaften“. Navigieren Sie zu „An

Tutorial: Wie lösche ich ein normales Benutzerkonto im Ubuntu-System? Tutorial: Wie lösche ich ein normales Benutzerkonto im Ubuntu-System? Jan 02, 2024 pm 12:34 PM

Dem Ubuntu-System wurden viele Benutzer hinzugefügt. Ich möchte die Benutzer löschen, die nicht mehr verwendet werden. Werfen wir einen Blick auf das ausführliche Tutorial unten. 1. Öffnen Sie die Terminal-Befehlszeile und löschen Sie den angegebenen Benutzer mit dem Befehl „sudo“ (siehe Abbildung unten). 2. Achten Sie beim Löschen darauf, dass Sie sich im Administratorverzeichnis befinden Sie verfügen nicht über diese Berechtigung, wie in der folgenden Abbildung dargestellt. 3. Wie kann nach der Ausführung des Löschbefehls beurteilt werden, ob er tatsächlich gelöscht wurde? Als nächstes verwenden wir den Befehl cat, um die passwd-Datei zu öffnen, wie in der Abbildung unten gezeigt. 4. Wir sehen, dass sich die gelöschten Benutzerinformationen nicht mehr in der passwd-Datei befinden, was beweist, dass der Benutzer gelöscht wurde, wie in der folgenden Abbildung gezeigt 5. Dann geben wir die Home-Datei ein

Was ist Sudo und warum ist es wichtig? Was ist Sudo und warum ist es wichtig? Feb 21, 2024 pm 07:01 PM

sudo (Superuser-Ausführung) ist ein Schlüsselbefehl in Linux- und Unix-Systemen, der es normalen Benutzern ermöglicht, bestimmte Befehle mit Root-Rechten auszuführen. Die Funktion von sudo spiegelt sich hauptsächlich in den folgenden Aspekten wider: Bereitstellung von Berechtigungskontrolle: sudo erreicht eine strikte Kontrolle über Systemressourcen und sensible Vorgänge, indem es Benutzern erlaubt, vorübergehend Superuser-Berechtigungen zu erhalten. Normale Benutzer können über sudo bei Bedarf nur vorübergehende Berechtigungen erhalten und müssen sich nicht ständig als Superuser anmelden. Verbesserte Sicherheit: Durch die Verwendung von sudo können Sie die Verwendung des Root-Kontos bei Routinevorgängen vermeiden. Die Verwendung des Root-Kontos für alle Vorgänge kann zu unerwarteten Systemschäden führen, da für jeden fehlerhaften oder nachlässigen Vorgang die vollen Berechtigungen gewährt werden. Und

Die Installation von Windows 11 KB5031455 schlägt fehl, was bei einigen Benutzern zu anderen Problemen führt Die Installation von Windows 11 KB5031455 schlägt fehl, was bei einigen Benutzern zu anderen Problemen führt Nov 01, 2023 am 08:17 AM

Microsoft hat damit begonnen, KB2 als optionales Update für Windows 503145511H22 oder höher der Öffentlichkeit zugänglich zu machen. Dies ist das erste Update, das die Funktionen von Windows 11 Moment 4 standardmäßig aktiviert, darunter Windows Copilot in unterstützten Bereichen, Vorschauunterstützung für Elemente im Startmenü, Aufheben der Gruppierung der Taskleiste und mehr. Darüber hinaus werden mehrere Fehler in Windows 11 behoben, darunter potenzielle Leistungsprobleme, die zu Speicherverlusten führten. Aber ironischerweise wird das optionale Update für September 2023 eine Katastrophe für Benutzer sein, die versuchen, das Update zu installieren, oder sogar für diejenigen, die es bereits installiert haben. Viele Benutzer werden dieses WLAN nicht installieren

Analyse des Speichermechanismus für Benutzerkennwörter im Linux-System Analyse des Speichermechanismus für Benutzerkennwörter im Linux-System Mar 20, 2024 pm 04:27 PM

Analyse des Speichermechanismus für Benutzerkennwörter im Linux-System Im Linux-System ist die Speicherung des Benutzerkennworts einer der sehr wichtigen Sicherheitsmechanismen. In diesem Artikel wird der Speichermechanismus von Benutzerkennwörtern in Linux-Systemen analysiert, einschließlich der verschlüsselten Speicherung von Kennwörtern, des Kennwortüberprüfungsprozesses und der sicheren Verwaltung von Benutzerkennwörtern. Gleichzeitig wird anhand konkreter Codebeispiele der tatsächliche Ablauf der Passwortspeicherung demonstriert. 1. Verschlüsselte Speicherung von Passwörtern In Linux-Systemen werden Benutzerpasswörter nicht im Klartext im System gespeichert, sondern verschlüsselt und gespeichert. L

See all articles