oracle 多表update,索引失效

本文针对非唯一键关联的两张表进行高效数据更新的问题,提出了通过创建临时表并利用主键匹配来显著提升更新操作的速度,从原来的4分钟缩短至4秒。

   这两天在写一个sql,就是有A,B两个表,要利用b表的字段更新a表对应的字段。形如

update A set A.a=(select B.b from B where A.id=B.id);

 这是一个非常常见的更新查询,但是在实际使用中,我要更新的a表和b表并不是主键相关,而是一个非唯一键相等,这样在实际中,观察执行计划发现根本不走索引,尽管我在A和B的相关字段上都添加了索引,甚至使用了

hint-/*+ index()*/ ,但是依然无效,在25w大小的数据量面前,两个全表查询连接完全无法接受。

update /*+  index(t INDEX_FLAG) */ t_download_temp t set t.status= (select /*+ index (t1 INDEX_URL_TEMP)*/  t1.url from t_download_temp t1 where t1.url=t.referer) where t.flag=1 and t.status=0                  

 

 

后来经过思考我采用了如下方案得到了较好的效果

 

 

 

truncate table t_download_temp2;
insert into t_download_temp2 select t.id mid,max(t1.referer) rurl,max(t1.id) rid,max(t1.status) rstatus from t_download_temp t ,t_download_temp t1 where t.referer_ref=t1.url and t.flag=1 and t.status=0 group by t.id;

  实质就是先做select * from A,B where A.c=B.c(非主键)

然后insert到一个临时表,其中在临时表中存入A的主键,并对临时表设置主键。

 

update (select t1.*,t2.* from t_download_temp t1,t_download_temp2 t2 where t1.id=t2.id)
set status=rstatus ,refererid=rid,referer_ref=RURL;

 

 

然后采用oracle中主键相等可以采用的一种更新方式如上,这样总运行时间只花掉了4s左右,对比之前的sql

 

4分钟没有跑出结果,速度完全可以接受

<think>嗯,用户问的是连接查询是否会导致索引失效,以及原因和解决方法。首先,我得回忆一下数据库索引的工作原理。索引主要是用来加速查询的,特别是在WHERE子句或者JOIN条件中。但连接的时候,如果操作当,确实可能导致索引失效,查询变慢。 那可能的原因有哪些呢?首先想到的是数据类型匹配。比如,如果连接的两个字段类型同,比如一个INT,一个VARCHAR,这时候数据库可能会使用索引,因为需要做隐式转换。还有,函数的使用,比如在JOIN条件里用了函数处理字段,比如UPPER(name),这会导致索引无法应用,因为索引存储的是原始值,是函数处理后的值。 然后是统计信息过时的问题。如果的统计信息没有及时更新,优化器可能会选择错误的执行计划,导致索引未被使用。比如,当数据量变化很大,但统计信息没更新,优化器可能误判索引的选择性高,从而选择全扫描。 关联顺序当也是一个原因。连接时,优化器需要决定先访问哪个,如果顺序合理,可能导致中间结果集过大,即使有索引也无法有效利用。比如,小应该先连接,减少后续处理的数据量,但如果优化器选错了顺序,可能会影响索引的使用。 还有复合索引的字段顺序问题。比如复合索引是(a,b),但查询条件里只用了b,这时候索引可能会被使用,因为符合最左前缀原则。这时候需要调整索引的顺序,或者单独为b字段建立索引。 另外,索引选择性低也是一个因素。如果某个字段的值重复率很高,比如性别字段,建立索引的意义大,优化器可能会忽略这个索引,直接全扫描。 至于解决方法,首先检查连接条件的数据类型是否一致,避免隐式转换。然后避免在连接字段上使用函数或达式,保持字段的原始状态。更新统计信息也很重要,确保优化器有最新的数据分布信息。调整关联顺序可能需要使用提示(HINT)或者优化查询结构。复合索引的顺序需要根据查询需求来设计,必要时增加单列索引。对于索引选择性低的字段,可能需要重新评估是否需要索引,或者采用其他优化手段,比如分区。 用户可能实际遇到的情况是,他们的查询突然变慢,检查执行计划发现没有索引,这时候需要逐一排查这些可能的原因。比如,他们可能在JOIN的时候用了函数,或者字段类型匹配,导致索引失效。另外,统计信息过时也是一个常见问题,尤其是在频繁更新的中,可能需要定期分析来更新统计信息。</think>### 连接查询索引失效原因及解决方法 #### 一、索引失效的常见原因 1. **数据类型匹配** 若连接字段(如`JOIN ON`条件)的数据类型一致,数据库可能触发隐式类型转换,导致无法使用索引。例如: ```sql -- A的user_id是INT,B的user_code是VARCHAR SELECT * FROM tableA JOIN tableB ON tableA.user_id = tableB.user_code; -- 索引失效 ``` 2. **函数或达式处理连接字段** 在连接条件中对字段进行函数操作(如`UPPER()`、`DATE()`)或计算(如`+1`),会破坏索引的直接匹配性。例如: ```sql SELECT * FROM orders JOIN users ON UPPER(orders.user_name) = UPPER(users.name); -- 索引失效 ``` 3. **统计信息过时** 数据库优化器依赖统计信息选择执行计划。若的统计信息未及时更新(如大范围数据增删后未执行`ANALYZE`),可能导致优化器误判索引成本,选择全扫描[^1]。 4. **关联顺序当** 连接时,若优化器选择的关联顺序合理(如优先连接大),可能导致中间结果集过大,后续步骤即使有索引也难以优化。例如: ```sql -- 若products有100万行,orders有10万行 SELECT * FROM products JOIN orders ON products.id = orders.product_id; -- 未优先过滤小 ``` 5. **复合索引设计问题** 复合索引的字段顺序未遵循查询需求。例如: ```sql -- 复合索引为 (category, price) SELECT * FROM products JOIN categories ON products.category = categories.name WHERE products.price > 100; -- 若未包含category条件,复合索引可能失效 ``` 6. **索引选择性低** 若连接字段的重复值过(如性别、状态标志),索引的选择性较低,优化器可能直接跳过索引。 --- #### 二、优化方法与解决方案 1. **确保数据类型一致性** 统一连接字段的数据类型,避免隐式转换。例如将`VARCHAR`字段改为`INT`,或显式转换: ```sql SELECT * FROM tableA JOIN tableB ON tableA.user_id = CAST(tableB.user_code AS INT); ``` 2. **避免函数操作连接字段** 预处理数据或调整结构,直接存储处理后的值。例如新增`user_name_upper`字段并建立索引: ```sql ALTER TABLE users ADD COLUMN name_upper VARCHAR(255); UPDATE users SET name_upper = UPPER(name); CREATE INDEX idx_users_name_upper ON users(name_upper); ``` 3. **定期更新统计信息** 对大或高频更新的执行统计信息更新: ```sql ANALYZE TABLE orders, users; -- MySQL EXEC DBMS_STATS.GATHER_TABLE_STATS('SCHEMA_NAME', 'TABLE_NAME'); -- Oracle ``` 4. **优化关联顺序** - **手动指定关联顺序**:通过子查询或临时优先过滤小数据集 ```sql SELECT * FROM (SELECT * FROM orders WHERE status = 'paid') AS filtered_orders JOIN products ON filtered_orders.product_id = products.id; ``` - **使用优化器提示**(需谨慎): ```sql /*+ LEADING(t1 t2) USE_NL(t2) */ -- Oracle提示优先连接t1并使用嵌套循环 ``` 5. **合理设计复合索引** 根据实际查询条件调整索引字段顺序,或补充单列索引。例如: ```sql -- 原复合索引 (category, price) -- 新增单列索引 CREATE INDEX idx_products_price ON products(price); ``` 6. **使用覆盖索引减少I/O** 若查询只需索引字段,可设计覆盖索引避免回: ```sql CREATE INDEX idx_orders_product_status ON orders(product_id, status); SELECT product_id, status FROM orders JOIN products ...; -- 直接使用索引 ``` --- #### 三、验证索引是否生效的方法 1. **执行计划分析** 使用`EXPLAIN`或`EXPLAIN ANALYZE`查看是否命中索引: ```sql EXPLAIN SELECT * FROM orders JOIN users ON orders.user_id = users.id; ``` - 输出中若出现`Using index`或`Index Scan`,索引生效。 2. **性能监控工具** 通过数据库自带的监控工具(如MySQL的Performance Schema、PG的pg_stat_statements)观察查询耗时和资源消耗。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值