filter造成的性能问题

本文探讨了SQL查询中filter的应用及其对数据过滤的影响,并通过一个具体的查询案例展示了如何理解和优化复杂的SQL执行计划。文中还提供了针对特定表的索引创建建议以提高查询效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

      filter这个词总让人很费解,它下一级可以挂 一个子节点,二个节点,三个子节点...。

     挂一个子节点意思过滤,如对全表进行扫描后,按照条件过滤,丢弃不满足条件的数据。

     挂二个子节点类似是nest loop。

     挂三个子节点类似1和2做nest loop,结果集再与3做nest loop(这个是我推测的)。

SQL> set linesize 300
SQL> set timing on
SQL> set autotrace traceonly
SQL> SELECT count(DISTINCT BI.RISK_BASE_ID) count
  2    FROM GG_RISK_BASE_INFO           BI,
  3         GG_TASK_FORM_CLASSTEMPLATE   FC,
  4         GG_TASK_FORM_TEMPLATEVERSION FT,
  5         GG_TASK_FORM_RELATIONTEMPLAT FR,
  6         GG_TASK_WORK_SHEET           WS,
  7         GG_TASK_FORM_EXETASKRECORD   FE
  8   WHERE FC.RISK_BASE_ID = BI.RISK_BASE_ID
  9     and FT.TEMPLATE_FID = FC.TEMPLATE_ID
 10     and FR.TEMPLATE_VERSION_ID = FT.TEMPLATE_VERSION_ID
 11     and FR.OBJECT_ID = WS.WORK_SHEET_ID
 12     and FE.REL_TEMP_ID = FR.REL_TEMP_ID
 13     and FR.REL_OBJECT_TYPE = '1'
 14     AND FE.TASK_START_TIME > BI.RISK_ASSESS_TIME
 15     and (exists
 16          (SELECT 1
 17             FROM GG_TASK_FORM_RISK_CTL_LOG CL
 18            where CL.TEMPLATE_VERSION_ID = FT.TEMPLATE_VERSION_ID) or exists
 19          (SELECT 1
 20             FROM GG_TASK_FORM_NEW_RISK_INFO RI
 21            where RI.REL_TEMP_ID = FR.REL_TEMP_ID));


已用时间:  00: 04: 10.36
执行计划


数据规模:
select count(1) from GG_RISK_BASE_INFO; --2828 
select count(1) from GG_TASK_FORM_CLASSTEMPLATE;  --5600 
select count(1) from GG_TASK_FORM_TEMPLATEVERSION;  --7646 
select count(1) from GG_TASK_FORM_EXETASKRECORD;  --33064 
select count(1) from GG_TASK_FORM_RELATIONTEMPLAT;  --67319  
select count(1) from GG_TASK_FORM_RISK_CTL_LOG;--5210
select count(1) from GG_TASK_FORM_NEW_RISK_INFO;--27831


CREATE INDEX IDX_PTNRI_REL_TEMP_ID ON GG_TASK_FORM_NEW_RISK_INFO(REL_TEMP_ID);
CREATE INDEX IDX_PTFRCL_REL_T_V_ID ON GG_TASK_FORM_RISK_CTL_LOG(TEMPLATE_VERSION_ID);



<think>我们被要求通过SQL语句检测锁和事务对性能影响。结合之前的讨论,我们可以使用数据库提供的系统视图和动态管理视图(DMV)来监控锁和事务的状态。以下是一些针对不同数据库系统的实用查询:###一、通用方法(以SQLServer为例)####1.查看当前阻塞的会话```sqlSELECTblock.session_idASblocking_session_id,wait.resource_description,wait.wait_type,wait.wait_duration_ms,sess.[text]ASblocking_sql_textFROMsys.dm_os_waiting_tasksASwaitINNERJOINsys.dm_exec_requestsASblockONwait.blocking_session_id=block.session_idCROSSAPPLYsys.dm_exec_sql_text(block.sql_handle)ASsessWHEREwait.session_id>50;--排除系统会话```此查询显示哪些会话正在阻塞其他会话,以及阻塞的SQL语句和等待时间[^2]。####2.事务执行时间分析(配合时间统计)```sqlSETSTATISTICSTIMEON;--启用时间统计[^5]GOBEGINTRAN;UPDATEAccountsSETBalance=Balance-100WHEREAccountID=1;--示例事务COMMIT;GOSETSTATISTICSTIMEOFF;```在消息输出中可以看到实际执行时间和CPU时间,长时间持有事务可能意味着锁竞争[^5]。###二、MySQL检测方法####1.查看当前锁等待```sqlSELECTr.trx_idASwaiting_trx_id,r.trx_mysql_thread_idASwaiting_thread,b.trx_idASblocking_trx_id,b.trx_mysql_thread_idASblocking_thread,b.trx_queryASblocking_query,r.trx_queryASwaiting_queryFROMinformation_schema.innodb_lock_waitswINNERJOINinformation_schema.innodb_trxbONb.trx_id=w.blocking_trx_idINNERJOINinformation_schema.innodb_trxrONr.trx_id=w.requesting_trx_id;```此查询直接显示哪个事务阻塞了哪个事务[^3]。####2.查看长事务(可能导致锁保持时间过长)```sqlSELECT*FROMinformation_schema.innodb_trxWHERETIME_TO_SEC(TIMEDIFF(NOW(),trx_started))>60;--超过60秒的事务```长时间运行的事务可能会持有锁,导致其他事务阻塞[^3]。###三、PostgreSQL检测方法####1.锁竞争分析```sqlSELECTpidASblocked_pid,usenameASblocked_user,queryASblocked_query,age(now(),query_start)ASblocking_durationFROMpg_stat_activityWHEREwait_event_type='Lock';```显示当前因锁等待而被阻塞的会话及其等待时间[^4]。###四、使用性能模式(MySQL)```sql--查看阶段事件(包括锁时间)SELECT*FROMperformance_schema.events_stages_historyWHEREevent_nameLIKE'%wait/synch/mutex/innodb%';```通过性能模式可以分析各种等待事件,包括锁等待[^1]。###五、关键指标解释|指标|警戒值|说明||------------------------|----------------------|------||锁等待时间|>500ms|超过此值表明严重锁争用[^2]||事务持续时间|>事务平均时间300%|异常长事务可能阻塞系统||锁等待会话比例|>10%|系统范围锁问题信号[^3]|###六、操作建议1.**结合执行计划分析**:对长时间运行的查询使用`EXPLAIN`检查索引使用[^1]2.**降低隔离级别**:读多写少场景考虑`READCOMMITTED`[^2]3.**分批次提交**:大事务拆分为小事务减少锁持有时间例如,将大更新操作拆分:```sqlWHILEEXISTS(SELECT1FROMOrdersWHEREstatus='pending'ANDupdate_time< DATEADD(hour,-1,GETDATE()))BEGINUPDATETOP(1000)OrdersSETstatus='processed'WHEREstatus='pending'ANDupdate_time< DATEADD(hour,-1,GETDATE());COMMIT;WAITFORDELAY'00:00:01';--暂停1秒释放锁END```###§§相关问题§§1.如何区分行锁和表锁造成的性能问题?2.数据库死锁发生时如何自动捕获详细信息?3.事务隔离级别调整后如何验证性能改善效果?</think> 以下是用于检测锁和事务对数据库性能影响的实用SQL语句,按数据库类型分类并提供关键分析指标: ### 一、SQL Server 检测方案 #### 1. 锁等待分析(实时阻塞检测) ```sql SELECT wt.blocking_session_id AS 阻塞会话ID, db.name AS 数据库名, wt.wait_duration_ms/1000.0 AS 等待时间_秒, wt.wait_type AS 等待类型, st.text AS 被阻塞SQL, blo.text AS 阻塞SQL FROM sys.dm_os_waiting_tasks wt JOIN sys.databases db ON db.database_id = wt.resource_database_id CROSS APPLY sys.dm_exec_sql_text(wt.sql_handle) st CROSS APPLY sys.dm_exec_sql_text( (SELECT sql_handle FROM sys.sysprocesses WHERE spid = wt.blocking_session_id) ) blo WHERE wt.wait_type LIKE 'LCK_%' -- 锁相关等待 AND wt.wait_duration_ms > 2000; -- 超过2秒的等待 ``` **关键指标**:等待时间 > 2秒 表明严重锁竞争[^2] #### 2. 事务运行时分析(需在事务执行前启用) ```sql SET STATISTICS TIME ON; -- 启用时间统计[^5] SET STATISTICS IO ON; BEGIN TRAN UPDATE Accounts SET Balance = Balance - 100 WHERE AccountID = 1; -- 示例事务 COMMIT TRAN SET STATISTICS TIME OFF; SET STATISTICS IO OFF; ``` **输出分析**: `SQL Server Execution Times`中的`Elapsed time`若超过300ms需优化 `Scan count`值过高表明索引缺失 --- ### 二、MySQL 检测方案 #### 1. 长事务检测(InnoDB引擎) ```sql SELECT trx_id AS 事务ID, TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) AS 持续时间_秒, trx_query AS 当前SQL, trx_operation_state AS 操作状态 FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 5; -- 超过5秒的事务 ``` **风险阈值**:事务持续时间 > 5秒 可能导致锁堆积[^3] #### 2. 锁等待关系图谱 ```sql SELECT r.trx_id AS 请求事务ID, b.trx_id AS 阻塞事务ID, r.trx_query AS 被阻塞SQL, b.trx_query AS 阻塞SQL, TIMEDIFF(NOW(), r.trx_wait_started) AS 等待时间 FROM information_schema.INNODB_LOCK_WAITS w JOIN information_schema.INNODB_TRX r ON r.trx_id = w.requesting_trx_id JOIN information_schema.INNODB_TRX b ON b.trx_id = w.blocking_trx_id; ``` --- ### 三、PostgreSQL 检测方案 #### 1. 锁状态全景视图 ```sql SELECT pid AS 进程ID, age(now(), query_start) AS 运行时长, usename AS 用户名, query AS 当前SQL, mode AS 锁模式, granted AS 是否已获锁 FROM pg_locks l JOIN pg_stat_activity a ON a.pid = l.pid WHERE NOT l.granted; -- 未获批准的锁请求 ``` #### 2. 死锁自动记录分析 ```sql SELECT query, EXTRACT(epoch FROM (NOW() - query_start)) AS 执行秒数, wait_event_type AS 等待类型 FROM pg_stat_activity WHERE wait_event_type = 'Lock' -- 锁等待事件 AND state = 'active'; ``` --- ### 四、跨平台通用检测技巧 #### 1. 解释计划分析(任何支持EXPLAIN的数据库) ```sql EXPLAIN ANALYZE -- [^1] UPDATE products SET stock = stock - 1 WHERE product_id IN (SELECT product_id FROM orders WHERE status='unpaid'); ``` **关注点**: - `Seq Scan` 出现表明全表扫描 - `LockRows` 操作耗时异常 - `Rows Removed by Filter` 值过高 #### 2. 事务日志分析 ```bash # MySQL错误日志分析(Linux) grep "lock wait timeout" /var/log/mysql/error.log # SQL Server事务日志 SELECT * FROM fn_dblog(NULL, NULL) WHERE Operation IN ('LOP_BEGIN_XACT','LOP_COMMIT_XACT'); ``` --- ### 五、关键性能指标阈值 | 检测项 | 警告阈值 | 危险阈值 | 应对措施 | |-----------------------|---------------|----------------|------------------------------| | 单事务执行时间 | >300ms | >1000ms | 事务拆分/索引优化[^1] | | 锁等待比例 | >10% | >25% | 降低隔离级别[^2] | | 死锁发生率 | >2次/分钟 | >5次/分钟 | 调整锁顺序/NOLOCK提示 | | 长事务占比 | >5% | >15% | 设置事务超时[^4] | | 日志刷新延迟 | >20ms | >100ms | 优化日志文件组 | --- ### 六、优化效果验证示例 优化前事务: ```sql BEGIN TRAN UPDATE Accounts SET balance = balance - 100 WHERE user_id=123; UPDATE Transactions SET amount=100 WHERE ref_id=987; -- 持有锁10秒 COMMIT ``` 优化后效果验证: ```sql SET STATISTICS TIME ON; BEGIN TRAN UPDATE Accounts ... -- 0.2s UPDATE Transactions ... -- 0.3s COMMIT -- 总耗时: 0.52s (原12.4s) ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值