从隐式转换案例,来挖掘开发人员的技能提升

前几天在墨天轮的论坛上,碰到个问题(https://www.modb.pro/issue/1440),有点意思,值得在这说下。

问题说明:

TBL_TallyABC存在联合主键,

WorkDate,ReceiveDate,StatDate,BillCycle,SettlementOrgID,StatType

SQL的执行计划是全表扫描,

update TBL_TallyABC set Count = Count + 1,Amount = Amount + :1
where WorkDate = :2 and ReceiveDate = :3 and StatDate = :4 and
BillCycle = :5 and SettlementOrgID = :6 and StatType = :7

发现这个SQL造成数据库高峰时段75%的enq: TX - row lock contention等待事件,且锁的模型是6是什么原因呢,怎样减少enq: TX - row lock contention?

从上面的信息,可以知道这几点,

1. update语句的where条件字段都是复合索引的字段。

2. 但是update语句没用上索引,为全表扫描。

3. 执行update语句期间,数据库出现enq: TX - row lock contention争用。

基于以上信息,推测之所以出现行锁争用,是这样的逻辑,


当对表行进行DML操作的时候,需要获取相应锁,enq: TX - row lock contention就是行锁争用,之所以出现这个争用,就是因为UPDATE用了全表扫描,导致一条SQL的执行时间比以前更久,大量UPDATE操作,雪崩效应,就会让行锁争用更明显。

朋友虽然没给出这个问题中具体的表结构、绑定变量值,但是,我们是可以反推出实验的,如下所示,表t_001,含三个字段,分别是timestamp、date和number类型,此时,创建(timestamp, date, number)复合索引,

SQL> create table t_001(a_ts timestamp, a_date date, id number);
Table created.

SQL> alter table t_001 add constraint pk_t_001 primary key(a_ts, a_date, id);
Table altered.

执行select,where条件涉及时间的,统一使用to_date转成date类型,左值a_ts字段是timestamp类型,右值date类型,因为timestamp优先级高于date,因此在这左值不用隐式转换,从使用的索引唯一扫描就能证明这点,复合索引的三个字段都用上了,

SQL> select * from t_001 where id = 1 and a_ts  = to_date('2020-02-15','yyyy-mm-dd') and 
  2  a_date = to_date('2020-02-15','yyyy-mm-dd');

no rows selected


Execution Plan
----------------------------------------------------------
Plan hash value: 76550962

------------------------------------------------------------------------------
| Id  | Operation         | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |          |     1 |    35 |     0   (0)| 00:00:01 |
|*  1 |  INDEX UNIQUE SCAN| PK_T_001 |     1 |    35 |     0   (0)| 00:00:01 |
------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("A_TS"=TIMESTAMP' 2020-02-15 00:00:00' AND
              "A_DATE"=TO_DATE(' 2020-02-15 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND
              "ID"=1)

但是,当使用下面的SQL,where条件涉及时间的统一使用to_timestamp转成timestamp类型,左值a_date是date类型,右值转成timestamp类型,因为timestamp优先级高于date,此时左值会进行隐式转换,需要将date转成timestamp,而且从谓词信息,可以看到,Oracle对a_date使用了INTERNAL_FUNCTION函数,对字段使用了函数操作,就会导致字段上的索引失效,谓词从access改为了filter,这个复合索引,仅可用到其中一部分字段,其他字段只能作为过滤条件,从使用的索引范围扫描就能证明这个推测,

SQL> select * from t_001 where id = 1 and a_ts  = to_timestamp('2020-02-15 00:01:00','yyyy-mm-dd hh24:mi:ss')
  2  and a_date = to_timestamp('2020-02-15 00:01:00','yyyy-mm-dd hh24:mi:ss');

no rows selected


Execution Plan
----------------------------------------------------------
Plan hash value: 491049371

-----------------------------------------------------------------------------
| Id  | Operation        | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT |          |     1 |    35 |     0   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| PK_T_001 |     1 |    35 |     0   (0)| 00:00:01 |
-----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("A_TS"=TIMESTAMP' 2020-02-15 00:01:00.000000000' AND
              "ID"=1)
       filter("ID"=1 AND INTERNAL_FUNCTION("A_DATE")=TIMESTAMP'
              2020-02-15 00:01:00.000000000')

隐式转换,说白了,就是当where条件“=”号右值的优先级高于“=”号左值的优先级,此时就需要对左值进行函数操作,借此转换成和右值相同的类型,就像Oracle中nvarchar2、varchar2、char以及timestamp和date。

以下是和隐式转换相关的历史文章,

浅谈显式转换和隐式转换

隐式转换的案例场景

一次有意思的错选执行计划问题定位


对这个问题,如果各位有什么其他的见解,欢迎在文末留言,我们一同探讨。

然而,实际情况是,开发人员很可能因为对字段类型的错误理解,导致写出来的程序出现隐式转换,而且在测试环境,数据量很小,这种性能问题是不能暴露出来的,可到了生产环境,他就会对系统的稳定运行产生影响。

因此,作为开发人员,除了需要了解数据库的CRUD,对可能产生性能隐患的一些数据库基础知识同样需要了解,不能做code的搬运工,而是要做创造者,才可能提升自己的个人价值。

当你要确定自己写的SQL代码在性能上是否存在隐患的时候,就可能会用到执行计划,你要知道怎么得到真实的执行计划,判断执行计划的正确,根据执行计划纠正自己的SQL。

当你要对表结构做调整,例如增加字段、删除字段,你可能需要了解在执行过程中他会持有什么级别的锁,知道这个操作对数据库有什么影响。

当你要删除大表数据,或者更新大表数据的时候,你可能需要根据实际情况,以及对数据库原理的理解,来判断选择合适的方案,方案选择的对,可能秒级完成,否则,几个小时都未必能完成。

其实像这样的例子还很多,开发人员对数据库原理了解的越多,就会越让你在关键时刻做出正确的判断。

当然,这些都取决于你在日常的积累。我这个杂货铺就是了解这些知识的渠道之一,这张图是杂货铺中和Oracle相关的文章分类,其中一些是站在开发人员的角度讲解的知识,或是碰到的实际问题,欢迎各位品读、尝试和讨论,

近期热文:

公众号600篇文章分类和索引

Oracle ACE,一段不可思议的旅程

Oracle 19c之RPM安装

应用执行慢的问题排查路径

ACOUG年会感想

千万级表数据更新的需求

探寻大表删除字段慢的原因

一次Oracle bug的故障排查过程思考

新增字段的一点一滴技巧

对recursive calls的深刻理解

《Oracle Concept》第三章 - 12

幂等性

一次惊心动魄的问题排查

Java日期中“y”和“Y”的区别

英超梦幻之行

藤子不二雄博物馆之行

传控Tiki-Taka战术解惑

深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值