MySQL中使用UNION进行两表合并,去重导致效率低下,请问如何优化

MySQL中使用UNION进行两表合并,去重导致效率低下,请问如何优化,第1张

MySQL中使用UNION进行两表合并,去重导致效率低下,请问如何优化

mysql>explain select * from wp_options limit 1\G

id: 1

select_type: SIMPLE

table: wp_options

partitions: NULL

type: ALL

possible_keys: NULL

key: NULL

key_len: NULL

ref: NULL

rows: 136

filtered: 100.00

Extra: NULL

1 row in set, 1 warning (0.01 sec)

mysql>show session status like 'Handler_read%'

1、选取最适用的字段属性

MySQL可以很好的支持大数据量的存取,但是一般说来,数据库中的表越小,在它上面执行的查询也就会越快。因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得尽可能小。

2、使用连接(JOIN)来代替子查询(Sub-Queries)

MySQL从4.1开始支持SQL的子查询。这个技术可以使用SELECT语句来创建一个单列的查询结果,然后把这个结果作为过滤条件用在另一个查询中。例如,我们要将客户基本信息表中没有任何订单的客户删除掉,就可以利用子查询先从销售信息表中将所有发出订单的客户ID取出来,然后将结果传递给主查询。

3、使用联合(UNION)来代替手动创建的临时表

MySQL从4.0的版本开始支持union查询,它可以把需要使用临时表的两条或更多的select查询合并的一个查询中。在客户端的查询会话结束的时候,临时表会被自动删除,从而保证数据库整齐、高效。使用union来创建查询的时候,我们只需要用UNION作为关键字把多个select语句连接起来就可以了,要注意的是所有select语句中的字段数目要想同。下面的例子就演示了一个使用UNION的查询。

4、事务

尽管我们可以使用子查询(Sub-Queries)、连接(JOIN)和联合(UNION)来创建各种各样的查询,但不是所有的数据库 *** 作都可以只用一条或少数几条SQL语句就可以完成的。更多的时候是需要用到一系列的语句来完成某种工作。但是在这种情况下,当这个语句块中的某一条语句运行出错的时候,整个语句块的 *** 作就会变得不确定起来。设想一下,要把某个数据同时插入两个相关联的表中,可能会出现这样的情况:第一个表中成功更新后,数据库突然出现意外状况,造成第二个表中的 *** 作没有完成,这样,就会造成数据的不完整,甚至会破坏数据库中的数据。要避免这种情况,就应该使用事务,它的作用是:要么语句块中每条语句都 *** 作成功,要么都失败。换句话说,就是可以保持数据库中数据的一致性和完整性。事物以BEGIN关键字开始,COMMIT关键字结束。在这之间的一条SQL *** 作失败,那么,ROLLBACK命令就可以把数据库恢复到BEGIN开始之前的状态。

5、锁定表

尽管事务是维护数据库完整性的一个非常好的方法,但却因为它的独占性,有时会影响数据库的性能,尤其是在很大的应用系统中。由于在事务执行的过程中,数据库将会被锁定,因此其它的用户请求只能暂时等待直到该事务结束。如果一个数据库系统只有少数几个用户来使用,事务造成的影响不会成为一个太大的问题;但假设有成千上万的用户同时访问一个数据库系统,例如访问一个电子商务网站,就会产生比较严重的响应延迟。其实,有些情况下我们可以通过锁定表的方法来获得更好的性能。

6、使用外键

锁定表的方法可以维护数据的完整性,但是它却不能保证数据的关联性。这个时候我们就可以使用外键。

7、使用索引

索引是提高数据库性能的常用方法,它可以令数据库服务器以比没有索引快得多的速度检索特定的行,尤其是在查询语句当中包含有MAX(),MIN()和ORDERBY这些命令的时候,性能提高更为明显。

希望可以帮到你,谢谢!

范围访问方法使用一个索引来检索包含一个或多个索引间隔中的表行的子集。它可以使用索引中的一列或者多列,以下各节描述了优化器使用范围访问的条件

对于一个单列索引,索引值间隔可以方便地由 WHERE 条件中的相应条件表示,表示为范围条件而不是 intervals 。

上述的 常量 指以下情况之一:

以下是在 WHERE 子句中具有范围条件的查询示例

一些非常量可能会在优化器传播阶段转换为常量

MySQL对于每个可能使用的索引,尝试从 WHERE 子句中提取范围条件。在提取过程中,不能用于构建条件范围的条件被删除,产生重复范围的条件被合并,产生空范围的条件被删除。

假设有以下语句, key1 是一个被索引的列,而 nonkey 没有索引

提取 key1 索引的过程如下:

通常,范围扫描使用的条件比 WHERE 子句中的限制要少()。MySQL执行额外的检查来过滤满足范围条件但是不完全满足 WHERE 子句的行。

范围条件提取算法可以处理任意深度嵌套的 AND/OR 构造,并且它的输出不取决于条件在 WHERE 子句中出现的顺序

MySQL不支持为空间索引的 range 访问合并多个范围。要解决此限制,可以在相同的 SELECT 语句中使用 UNION 语句,将每个空间谓词放在不同的 SELECT 中。

多列索引的范围条件是单列索引的扩展,多列索引的范围条件将索引行限制在一个或多个索引元组的间隔中。索引元组间隔是一个按照索引顺序的,索引元组的集合。

假设有一个多列索引 key1(key_part1,key_part2,key_part3) ,按照索引顺序,具有以下键值元组列表

key_part1 = 1 定义了一个间隔: (1,-inf,-inf) <= (key_part1,key_part2,key_part3) <(1,+inf,+inf) ,这个间隔包括上面的第4、5、6个元组并且可以被用来进行范围访问。

但是, key_part3 = 'abc' 没有定义间隔并且不能被范围访问方法使用。

就是索引的最左前缀原则,B树索引是有序的,多列索引是首先按照第一列进行排序,然后在第一列排序的基础上,再对第二列数据进行排序,所以后面的列的顺序独立来看不是有序的,就不能单独用后面的列来进行排序或者范围访问的 *** 作。

对于 HASH 索引,只能使用包含相同值的每个间隔。这意味着只能针对以下形式的条件生成间隔:

这里, const1,const2... 是常量, cmp 是比较表达式: =,<=>,IS NULL ,并且条件覆盖所有的索引部分(就是说,如果有 N 个条件,那么每个条件都需要是一个 N列 索引的一部分)。例如:以下是一个三列 HASH 索引的一个范围条件

对于 BTREE 索引,一个间隔可以是使用 AND 组成的多个范围条件的集合,每个条件都将索引的一部分和一个常量使用 =,<=>,IS NULL,>,<,>=,<=,!=,<>,BETWEENT,LIKE 'pattern'(pattern不以通配符开始) 进行比较。只要可以确定与条件匹配的一个索引元组,就可以使用一个间隔( !=,<>使用两个间隔)

当比较运算符是 =,<=>,IS NULL 时,优化器尝试使用索引的其他部分来确定间隔。如果比较运算符是 >, <, >=, <=, !=, <>, BETWEEN, LIKE ,优化器使用索引,但不考虑索引中的其他列。

对于以下表达式,优化器使用第一个 = ,也会使用第二个 >= ,但是忽略其他索引部分,并且不将第三部分用作间隔构造。

key_part1 = 'foo' AND key_part2 >= 10 AND key_part3 >10

单个间隔为:

创建的间隔中可能包括比原始条件更多的行,比如,前面这个间隔可能会包括 ('foo',11,0) 这个值, 0<10 ,这个值不满足原始条件

如果覆盖间隔中的行集合的条件使用 OR 进行组合,则他们会形成间隔的并集。

如果条件使用 AND 进行组合,他们形成一个包括间隔交集的行集合。

示例:

这个在两列索引上的条件:

(key_part1 = 1 AND key_part2 <2) OR (key_part1 >5)

间隔是:

可以查看 EXPLAIN 输出中的 key_len 部分查看使用的索引前缀的最大长度。

在某些情况下, key_len 包括已使用的索引列,但是这个列可能不是你期望的,假设 key_part1 和 key_part2 可以为 NULL ,然后, key_len 显示以下条件的两个索引部分长度:

key_part1 >= 1 AND key_part2 <2

但是实际上,这个条件被转换为:

key_part1 >= 1 AND key_part2 IS NOT NULL

假设以下表达式, col_name 是一个索引的列

只要 col_name 等同于这些值中的任意一个,这个表达式结果就是 true 。这种比较是等值范围比较(其中的“范围”是一个单独的值)。

优化器按照以下方法,估算读取相等的值来进行等值范围比较的成本:

当使用 index dive 时,优化器在每个范围的末端进行 dive 并且使用该范围中的行数作为估算值。例如: col_name IN (10, 20, 30) 具有三个等值范围,优化器对每个范围进行两次 dive 以生成估算值。每次 dive 都会得出具有给定值的行数的估算值。

使用 index dive 提供了准确的行数估算值,但是随着表达式中要比较的值的数量增加,优化器需要使用更长的时间来生成行数的估算值。而使用索引统计信息的准确性不如直接使用索引,但是可以对大表进行更快的估算。

eq_range_index_dive_limit 选项可以控制优化器选择评估策略的值。要对 N 个等值范围使用 index dive ,将 eq_range_index_dive_limit 设置为 N+1 ,要禁用统计信息,总是使用 index dive ,将 eq_range_index_dive_limit 设置为0。

在MySQL8.0以前,除了使用 eq_range_index_dive_limit ,没有其他方法可以跳过 index dive 。在MySQL8.0中,当满足以下条件时,跳过 index dive :

对于 EXPLAIN FOR CONNECTION ,如果跳过了 index dive ,输出结果有所变更:

不包括 FOR CONNECTION 的 EXPLAIN 输出没有变化

在执行跳过 index dive 的查询后, INFORMATION_SCHEMA.OPTIMIZER_TRACE 表包含一个值为 skipped_due_to_force_index 的 index_dives_for_range_access 行

优化器可以对这种形式的查询进行范围扫描:

SELECT ... FROM t1 WHERE ( col_1, col_2 ) IN (( 'a', 'b' ), ( 'c', 'd' ))

要使用范围扫描,查询必须满足以下条件:

要控制有多少内存可以用来进行范围优化,使用 range_optimizer_max_mem_size 变量

使用以下原则估算范围扫描使用的内存:

IN() 中的每个值被当做使用 OR 结合的一个谓词。如果有两个 IN() 列表,每个列表中都是列表中的值的数量个谓词通过 OR 结合。在这种情况下,视作 M × N 个 谓词通过OR 结合。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/8689307.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-19
下一篇 2023-04-19

发表评论

登录后才能评论

评论列表(0条)

保存