SQL语句查询优化器认为是不同的SQL,需要解析两次

xzdxmynet 发布于 2024-01-26 阅读(41)

以上两条语句被查询优化器认为是不同的SQL语句,需要解析两次。如果使用了绑定变量

* 来自哪里 > @

@Variable可以传入任意值,这样大量相似的查询就可以复用执行计划,可以大大减轻数据库解析SQL语句的负担。 一次解析多次复用是提高数据库效率的原则。

倾斜字段的绑定变量监听问题

任何事情都有两个方面,绑定变量适用于大多数 OLTP 流程,但也有例外。 例如,当where条件中的字段是“倾斜字段”时。

“倾斜字段”意味着该列中的大部分值都是相同的。 例如,在一张人口普查表中,“民族”列中,90%以上的值都是汉族。 所以如果一条SQL语句想要查询30岁以上的汉族人口,那么“民族”列必须放在where条件中。 这时候如果使用绑定变量@,就会出现很大的问题。

试想一下,如果@传入的第一个值是“汉”,那么整个执行计划必然会选择表扫描。 然后,传入的第二个值是“Buyei”。 按理说,“布依”的比例可能只有万分之一,所以应该采用索引搜索。 但由于第一次解析的“汉”的执行计划被复用,所以第二次也会使用表扫描的方法。 这个问题就是著名的“绑定变量窥探”。 建议不要对“倾斜字段”使用绑定变量。

begin tran的事务应该尽可能小

在SQL中,一条SQL语句默认是一个事务,也是该语句执行后默认的一个事务。 事实上,这是begin tran的最小化形式,就像每条语句的开头隐含一个begin tran,末尾隐含一个。

在某些情况下,我们需要显式声明begin tran。 例如,在进行“增删改查”操作时,我们需要同时修改几个表。 要求几个表的修改要么全部成功,要么全部都不成功。 begin tran 可以起到这样的作用。 它可以将多个SQL语句一起执行,最后一起执行。 优点是保证了数据一致性,但没有什么是完美的。 Begin tran付出的代价是,在提交之前,所有被SQL语句锁定的资源都无法释放,直到释放为止。

可以看出,如果Begin tran陷阱的SQL语句过多,数据库的性能就会很差。 在大事务提交之前,其他语句不可避免地会被阻塞,从而产生大量的块。

Begin tran的使用原则是,在保证数据一致性的前提下,begin tran捕获的SQL语句越少越好! 有些情况下可以使用触发器来同步数据,不一定使用begin tran。

需要添加一些SQL查询语句

添加SQL语句是提高并发性能的重要手段。 SQL语句中不需要这样做,因为结构更合理。 有一个undo表空间来保存“数据伏笔”。 如果数据还没有被修改过,那么你读取到的就是修改前的副本,放在undo表空间中。 这样就可以做到读和写互不影响,这一点也广受好评。 读和写会互相阻塞。 为了提高并发性能,可以增加一些查询,这样读的时候就可以允许写,但缺点是可能会读到未提交的脏数据。 使用原则有3个。

(1)用于“插入、删除、修改”的查询结果不能添加!

(2) 所查询的表是频繁发生分页的表,请谨慎使用!

(3)使用临时表还可以节省“数据伏笔”,起到与undo表空间类似的作用。

如果可以使用临时表来提高并发性能,请不要使用它们。

查询添加后经常发生分页的表,很容易导致跳读或重复读。

添加后,可以一边“插入、删除、修改”进行查询,但由于“插入、删除、修改”同时发生,在某些情况下,一旦数据页满了,分页是不可避免的,而在此时正在发生查询。 例如,已经在第100页读取的记录可能由于分页而被划分到第101页。 这可能会导致查询在读取101页时重复读取数据,导致“重复读取”。 同理,如果第100页的数据在读取之前就分配到第99页,查询可能会漏掉该记录,导致“跳过”。

上面提到的朋友添加后报一些操作错误。 估计可能是查询造成了重复阅读。 如果两条相同的记录插入到其他表中,当然会发生主键冲突。

聚集索引不是建立在表的顺序字段上的,表容易出现页分裂。

例如,订单表具有订单号和客户号。 那么聚集索引应该添加到哪个字段呢? 对于该表,顺序号是按顺序添加的。 如果表中添加聚集索引,则新行会添加到最后,这样就不会频繁发生页拆分。 但是,由于大多数查询都是基于客户编号,因此只有为其添加聚集索引才有意义。 对于订单表来说,它不是一个顺序字段。

比如“张三”的“”是001,那么“张三”的订单信息就必须放在这个表的第一个数据页上。 如果“张三”​​今天下了新订单,那么订单信息就不能放在表格的最后一页,而是放在第一页! 如果第一页已满怎么办? 抱歉,该表中的所有数据都需要移回以为该记录腾出空间。

的索引与 的索引不同。 聚集索引实际上是按照聚集索引字段的顺序对表进行排序的,相当于索引组织表。 聚集索引是表本身的一种组织形式,因此它的效率非常高。 正因为如此,当插入一条记录时,它的位置并不是随机放置的,而是放在了它应该按顺序放置的数据页上。 如果该数据页上没有空间,就会导致页分裂。 所以很明显,聚集索引不是建立在表的顺序字段上的,表很容易出现页分裂。

我曾经遇到过一个情况,朋友对某个表重新建立索引后,插入效率明显下降。 估计情况大概是这样的。 表的聚集索引不能建立在表的顺序字段上。 该表经常被归档,因此该表的数据以稀疏状态存在。 例如,张三下了20个订单,但最近三个月只下了5个订单。 归档策略是保留3个月的数据。 那么张三过去的15笔订单已经被归档,留下了15个空缺,可以在交易发生时使用。 被重用。 在这种情况下,由于有可用空间,因此不会发生页面拆分。 但是查询性能会比较低,因为查询必须扫描那些没有数据的空白区域。

重建聚集索引后情况发生了变化,因为重建聚集索引意味着重新排列表中的数据。 原来的空白消失了,页面填充率非常高。 插入数据时经常会出现分页,导致性能明显下降。

对于聚集索引不是建立在顺序字段上的表,我们是否应该给出较低的页面填充率? 您想避免重建聚集索引吗? 是一个值得思考的问题!

使用复合索引提高多个where条件的查询速度

复合索引一般比单一索引具有更好的选择性。 而且,它是专门针对某种where条件而设置的索引。 已经排序了,所以查询速度比单个索引要快。 综合索引的主导字段必须是“高选择性”字段。 例如,有3个字段:日期、性别、年龄。 让我们看看,应该使用哪个字段作为引导字段? 显然“日期”应该用作主导字段。 日期是 3 个字段中最具选择性的。

这里有一个例外。 如果日期也是聚集索引的前导字段,可以不建复合索引,直接使用聚集索引,效率也更高。

不要将聚集索引构建为“复合索引”。 聚集索引越简单越好,选择性越高越好! 聚集索引包含2个字段,是可以容忍的。 但如果字段超过2个,就应该考虑创建一个自增字段作为主键。 聚集索引不需要是主键。

使用like进行模糊查询时,尽量不要使用第一个%。

有时需要进行一些模糊查询,例如

*'%悦%'

关键字%yue%,由于yue前面使用了“%”,所以查询必须扫描全表。 除非必要,不要在关键字前添加 %。

连接SQL表的三种方式

(1)

(2)

(3)

只有一种连接方法 - 如果结果集 A 较小,则默认将其用作外表面。 A 中的每条记录都会在 B 中被扫描。实际扫描的行数等于结果集 A 的行数 x 结果集 B 的行数。 所以如果两个结果集都很大,Join的结果就不好。

新增,如果A表和B表的连接字段恰好是聚集索引所在的字段,那么表的顺序已经排好,只需要两边进行join即可。 这个join的代价相当于A表结果集中的行数加上B表结果集中的行数,一个是加法,一个是乘法。 可以看到效果好多了。

如果连通域上没有索引,效率是相当低的。 但如果提供的话,就相当于临时给A表和B表的结果集增加了索引,因此效率大大提高。 我想这是一个重要的原因。

总结一下,连接表时要注意以下几点:

(1) 尽量选择聚集索引所在的字段作为连接字段。

(2)仔细考虑where条件,最小化表A和B的结果集。

(3)如果很多join连接字段缺少索引而您还在使用,请立即升级。

会引起表扫描,最好使用临时表分页

分页测试结果:

用于分页:CPU时间=毫秒,占用时间=毫秒

使用临时表进行分页:CPU时间=1266ms,占用时间=6705ms

实现是基于order by的,排序对查询的影响是显而易见的。

其他

比如有些写法会限制索引的使用

*g日期+7

标签:  聚集索引 sql优化 索引 

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。