为什么Mysql explain extended中的filtered列值总是100%
1. 问题
执行Mysql的explain extended的输出会比单纯的explain多一列filtered(MySQL5.7缺省就会输出filtered),它指返回结果的行占需要读到的行(rows列的值)的百分比。按说filtered是个非常有用的值,因为对于join操作,前一个表的结果集大小直接影响了循环的次数。但是我的环境下测试的结果却是,filtered的值一直是100%,也就是说失去了意义。参考下面mysql 5.6的代码,filtered值只对index和all的扫描有效(这可以理解,其它场合,通常rows值就等于估算的结果集大小。)。
sql/opt_explain.cc
- bool Explain_join::explain_rows_and_filtered()
- {
- if (table->pos_in_table_list->schema_table)
- return false;
- double examined_rows;
- if (select && select->quick)
- examined_rows= rows2double(select->quick->records);
- else if (tab->type == JT_INDEX_SCAN || tab->type == JT_ALL)
- {
- if (tab->limit)
- examined_rows= rows2double(tab->limit);
- else
- {
- table->pos_in_table_list->fetch_number_of_rows();
- examined_rows= rows2double(table->file->stats.records);
- }
- }
- else
- examined_rows= tab->position->records_read;
- fmt->entry()->col_rows.set(static_cast
(examined_rows)); - /* Add "filtered" field */
- if (describe(DESCRIBE_EXTENDED))
- {
- float f= 0.0;
- if (examined_rows)
- f= 100.0 * tab->position->records_read / examined_rows;
- fmt->entry()->col_filtered.set(f);
- }
- return false;
- }
但是,我构造了一个全表扫描后,filtered的结果却不对,仍然是100%,而我期待的是0.1%。
- mysql> desc tb2;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | 0 | |
| c1 | int(11) | YES | | NULL | |
| c2 | varchar(100) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
mysql> explain extended select * from tb2 where c1+----+-------------+-------+------+---------------+------+---------+------+--------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------+---------------+------+---------+------+--------+----------+-------------+
| 1 | SIMPLE | tb2 | ALL | NULL | NULL | NULL | NULL | 996355 | 100.00 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+--------+----------+-------------+
1 row in set, 1 warning (10 min 29.96 sec)
mysql> select count(*) from tb2 where c1+----------+
| count(*) |
+----------+
| 1001 |
+----------+
1 row in set (1.99 sec)
通过gdb跟踪,发现代码走的分支是对的,但下面的值有问题。
- (gdb) p table->file->stats.records
- $18 = 996355
- (gdb) p tab->position->records_read
- $19 = 996355
2.原因
为什么会出现上面的情况呢?后来我查看了下MySQL收集的统计信息就明白了。MySQL和其它主流数据库一样会自动需要收集统计信息以便生成更好的执行计划,也可以用analyze table手动收集,收集的统计信息存储在mysql.innodb_table_stats和mysql.innodb_index_stats里。
参考:http://dev.mysql.com/doc/refman/5.6/en/innodb-persistent-stats.html#innodb-persistent-stats-tables
但这不是重点,重点是,查看这两个表就会发现MySQL收集的统计信息非常少。
- mysql> select * from mysql.innodb_table_stats where table_name='tb2';
+---------------+------------+---------------------+--------+----------------------+--------------------------+
| database_name | table_name | last_update | n_rows | clustered_index_size | sum_of_other_index_sizes |
+---------------+------------+---------------------+--------+----------------------+--------------------------+
| test | tb2 | 2015-12-02 06:26:54 | 996355 | 3877 | 0 |
+---------------+------------+---------------------+--------+----------------------+--------------------------+
1 row in set (0.00 sec)
mysql> select * from mysql.innodb_index_stats where table_name='tb2';
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
| database_name | table_name | index_name | last_update | stat_name | stat_value | sample_size | stat_description |
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
| test | tb2 | PRIMARY | 2015-12-02 06:26:54 | n_diff_pfx01 | 996355 | 20 | id |
| test | tb2 | PRIMARY | 2015-12-02 06:26:54 | n_leaf_pages | 3841 | NULL | Number of leaf pages in the index |
| test | tb2 | PRIMARY | 2015-12-02 06:26:54 | size | 3877 | NULL | Number of pages in the index |
+---------------+------------+------------+---------------------+--------------+------------+-------------+-----------------------------------+
3 rows in set (0.00 sec)
3. 引申
后面我联系到MySQL匮乏的统计信息会带来什么后果?不难想象,如果缺少索引,MySQL很可能会生成性能糟糕的执行计划,比如搞错大表和小表的join顺序,就像下面这样。
- mysql> explain extended select count(*) from tb1,tb2 where tb1.c1=tb2.c1 and tb2.c2='xx';
+----+-------------+-------+------+---------------+------+---------+------+--------+----------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------+---------------+------+---------+------+--------+----------+----------------------------------------------------+
| 1 | SIMPLE | tb1 | ALL | NULL | NULL | NULL | NULL | 1000 | 100.00 | NULL |
| 1 | SIMPLE | tb2 | ALL | NULL | NULL | NULL | NULL | 996355 | 100.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------+---------------+------+---------+------+--------+----------+----------------------------------------------------+
2 rows in set, 1 warning (0.00 sec)
相同的查询,PostgreSQL给出的执行计划是更好的,先扫描t2表再循环扫描t1表。
- postgres=# explain select count(*) from tb1,tb2 where tb1.c1=tb2.c1 and tb2.c2='xx';
- QUERY PLAN
- -------------------------------------------------------------------
- Aggregate (cost=20865.50..20865.51 rows=1 width=0)
- -> Nested Loop (cost=0.00..20865.50 rows=1 width=0)
- Join Filter: (tb1.c1 = tb2.c1)
- -> Seq Scan on tb2 (cost=0.00..20834.00 rows=1 width=4)
- Filter: ((c2)::text = 'xx'::text)
- -> Seq Scan on tb1 (cost=0.00..19.00 rows=1000 width=4)
- (6 rows)
MySQL花了0.34s
- mysql> select count(*) from tb1,tb2 where tb1.c1=tb2.c1 and tb2.c2='xx';
- +----------+
- | count(*) |
- +----------+
- | 0 |
- +----------+
- 1 row in set (0.34 sec)
PostgreSQL花了0.139s
- postgres=# select count(*) from tb1,tb2 where tb1.c1=tb2.c1 and tb2.c2='xx';
- count
- -------
- 0
- (1 row)
- Time: 139.600 ms
上面这个例子的性能差别其实不是很大,如果去掉tb2.c2='xx'的条件,差别就非常大了。
Mysql花了1分08秒
- mysql> explain select count(*) from tb1,tb2 where tb1.c1=tb2.c1;
+----+-------------+-------+------+---------------+------+---------+------+--------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+--------+----------------------------------------------------+
| 1 | SIMPLE | tb1 | ALL | NULL | NULL | NULL | NULL | 1000 | NULL |
| 1 | SIMPLE | tb2 | ALL | NULL | NULL | NULL | NULL | 996355 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------+---------------+------+---------+------+--------+----------------------------------------------------+
2 rows in set (0.00 sec)
mysql> select count(*) from tb1,tb2 where tb1.c1=tb2.c1;
+----------+
| count(*) |
+----------+
| 9949 |
+----------+
1 row in set (1 min 8.26 sec)
PostgreSQL只用了0.163秒
- postgres=# explain select count(*) from tb1,tb2 where tb1.c1=tb2.c1;
- QUERY PLAN
- -------------------------------------------------------------------------
- Aggregate (cost=23502.34..23502.35 rows=1 width=0)
- -> Hash Join (cost=31.50..23474.97 rows=10947 width=0)
- Hash Cond: (tb2.c1 = tb1.c1)
- -> Seq Scan on tb2 (cost=0.00..18334.00 rows=1000000 width=4)
- -> Hash (cost=19.00..19.00 rows=1000 width=4)
- -> Seq Scan on tb1 (cost=0.00..19.00 rows=1000 width=4)
- (6 rows)
- Time: 0.690 ms
- postgres=# select count(*) from tb1,tb2 where tb1.c1=tb2.c1;
- count
- -------
- 10068
- (1 row)
- Time: 163.868 ms
不过这个性能差别和统计信息无关,原因在于PG支持Nest Loop Join,Merge Join和Hash Join,而MySQL只支持Nest Loop Join,缺了索引Nest Loop Join会慢得跟龟似的。
4. 总结
1. MySQL的统计信息非常少,只有表行数和索引列的唯一值数目,这使得MySQL的优化器经常不能对数据规模有一个正确的认识而给出性能不佳的执行计划。2.MySQL的join操作的效率非常依赖于索引(我之前两次帮人调优MySQL的SQL语句都是在加索引)。并不是说PG的join不需要索引,只是不像MySQL缺了索引的反应那么大。上面那个MySQL执行了1分多钟的例子,加上索引后,不管是MySQL还是PG的执行时间都立刻降到10毫秒以内。所以,开发人员在设计表的时候应该对可能的查询方式做个评估,把该建的索引都建上(不能少建也不宜多建)。
3.相比之下,PG不仅统计所有列的值分布,而且除了唯一值还有直方图,频繁值等等信息,支撑了PG的优化器做出正确的决策。猜测也是由于这个原因,PG社区认为PG的优化器已经足够智能,不需要把和Oracle类似的hint功能加到PG的内核里(因为hint可能会被人滥用,导致系统很难维护;不过,实在想用的话可以自己装pg_hint_plan插件)。

根据美国司法部的解释,蓝色警报旨在提供关于可能对执法人员构成直接和紧急威胁的个人的重要信息。这种警报的目的是及时通知公众,并让他们了解与这些罪犯相关的潜在危险。通过这种主动的方式,蓝色警报有助于增强社区的安全意识,促使人们采取必要的预防措施以保护自己和周围的人。这种警报系统的建立旨在提高对潜在威胁的警觉性,并加强执法机构与公众之间的沟通,以共尽管这些紧急通知对我们社会至关重要,但有时可能会对日常生活造成干扰,尤其是在午夜或重要活动时收到通知时。为了确保安全,我们建议您保持这些通知功能开启,但如果

Android中的轮询是一项关键技术,它允许应用程序定期从服务器或数据源检索和更新信息。通过实施轮询,开发人员可以确保实时数据同步并向用户提供最新的内容。它涉及定期向服务器或数据源发送请求并获取最新信息。Android提供了定时器、线程、后台服务等多种机制来高效地完成轮询。这使开发人员能够设计与远程数据源保持同步的响应式动态应用程序。本文探讨了如何在Android中实现轮询。它涵盖了实现此功能所涉及的关键注意事项和步骤。轮询定期检查更新并从服务器或源检索数据的过程在Android中称为轮询。通过

为了提升用户体验并防止数据或进度丢失,Android应用程序开发者必须避免意外退出。他们可以通过加入“再次按返回退出”功能来实现这一点,该功能要求用户在特定时间内连续按两次返回按钮才能退出应用程序。这种实现显著提升了用户参与度和满意度,确保他们不会意外丢失任何重要信息Thisguideexaminesthepracticalstepstoadd"PressBackAgaintoExit"capabilityinAndroid.Itpresentsasystematicguid

1.java复杂类如果有什么地方不懂,请看:JAVA总纲或者构造方法这里贴代码,很简单没有难度。2.smali代码我们要把java代码转为smali代码,可以参考java转smali我们还是分模块来看。2.1第一个模块——信息模块这个模块就是基本信息,说明了类名等,知道就好对分析帮助不大。2.2第二个模块——构造方法我们来一句一句解析,如果有之前解析重复的地方就不再重复了。但是会提供链接。.methodpublicconstructor(Ljava/lang/String;I)V这一句话分为.m

如何将WhatsApp聊天从Android转移到iPhone?你已经拿到了新的iPhone15,并且你正在从Android跳跃?如果是这种情况,您可能还对将WhatsApp从Android转移到iPhone感到好奇。但是,老实说,这有点棘手,因为Android和iPhone的操作系统不兼容。但不要失去希望。这不是什么不可能完成的任务。让我们在本文中讨论几种将WhatsApp从Android转移到iPhone15的方法。因此,坚持到最后以彻底学习解决方案。如何在不删除数据的情况下将WhatsApp

原因:1、安卓系统上设置了一个JAVA虚拟机来支持Java应用程序的运行,而这种虚拟机对硬件的消耗是非常大的;2、手机生产厂商对安卓系统的定制与开发,增加了安卓系统的负担,拖慢其运行速度影响其流畅性;3、应用软件太臃肿,同质化严重,在一定程度上拖慢安卓手机的运行速度。

1.启动ida端口监听1.1启动Android_server服务1.2端口转发1.3软件进入调试模式2.ida下断2.1attach附加进程2.2断三项2.3选择进程2.4打开Modules搜索artPS:小知识Android4.4版本之前系统函数在libdvm.soAndroid5.0之后系统函数在libart.so2.5打开Openmemory()函数在libart.so中搜索Openmemory函数并且跟进去。PS:小知识一般来说,系统dex都会在这个函数中进行加载,但是会出现一个问题,后

苹果公司周二向开发人员发布了iOS 16.2 beta 2,因为该公司准备在 12 月向公众提供更新。正式地,它添加了新的 Freeform 协作应用程序和对 Home 应用程序的改进。在后台,9to5Mac发现 Apple 一直在开发一种新的“自定义辅助功能模式”,该模式将为 iPhone 和 iPad 提供“流线型”体验。自定义辅助功能模式这种代号为“Clarity”的新模式基本上用更精简的模式取代了 Springboard(这是 iOS 的主要界面)。该功能在当前测试版中仍对用户不可用,将


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

SAP NetWeaver Server Adapter for Eclipse
Integrate Eclipse with SAP NetWeaver application server.

MinGW - Minimalist GNU for Windows
This project is in the process of being migrated to osdn.net/projects/mingw, you can continue to follow us there. MinGW: A native Windows port of the GNU Compiler Collection (GCC), freely distributable import libraries and header files for building native Windows applications; includes extensions to the MSVC runtime to support C99 functionality. All MinGW software can run on 64-bit Windows platforms.

Dreamweaver CS6
Visual web development tools

WebStorm Mac version
Useful JavaScript development tools