回答

收藏

如何告诉MySQL优化程序在派生表上使用索引?

技术问答 技术问答 369 人阅读 | 0 人回复 | 2023-09-14

假设您有这样的查询…) K8 g% u1 p# z! B
SELECT T.TaskID, T.TaskName, TAU.AssignedUsers+ r3 [/ C  s$ }5 L' G
FROM `tasks` T' `$ P: Q" L1 t6 a1 \9 O# Q
    LEFT OUTER JOIN (* F$ y# O; s! l
        SELECT TaskID, GROUP_CONCAT(U.FirstName, ' ',9 }9 V' e! p1 q0 M7 A2 Q$ u6 T# \
            U.LastName SEPARATOR ', ') AS AssignedUsers0 }3 e! y& ^$ a
        FROM `tasks_assigned_users` TAU3 \$ o# X$ z* D- r0 I9 H/ W& |
            INNER JOIN `users` U ON (TAU.UserID=U.UserID)) A2 S6 n$ ^( s. F3 f8 C
        GROUP BY TaskID
  t* y1 L9 V+ M# [    ) TAU ON (T.TaskID=TAU.TaskID)
) l# ~- u/ d2 b5 j, a7 I可以将多个人分配给给定任务。该查询的目的是显示每个任务一行,但将分配给该任务的人员显示在单个列中
- b' S4 M* A2 z" m; X) \( l现在…假设你有正确的指标设置上tasks,users和tasks_assigned_users。连接tasks到派生表时,MySQL: b  N* t6 j! f6 u
Optimizer仍将不使用TaskID索引。WTF?!?!?; R: @) Z2 H% `
因此,我的问题是…如何使此查询使用task_assigned_users.TaskID上的索引?临时表是la脚的,所以如果这是唯一的解决方案,那么MySQL
9 p& ^7 y0 e0 G; ]) ~Optimizer是愚蠢的。
1 M  e, F- ~$ j6 o使用的索引:" r" h, n. k: P2 j4 A% }& I7 ?
任务 % [$ u& Z  L/ B" x& D6 z# g2 E. k) @
主要-TaskID; u! e. S/ I2 m1 e# e( J# A" q  ]3 |
使用者
  b. V# X  C' A1 z- [主要-用户ID
! l. n( M8 Z7 ?% y) t8 @
task_assigned_users / t3 A. P, n5 }- K" H, ^5 V
主要-(TaskID,UserID), ]" a1 D  R9 b8 V
附加索引UNIQUE-(UserID,TaskID)
- e# {) e* g% h. [" ]
7 A# q* m" ~' M5 F: p, x
& Y. |( X( d; C" a' o8 L  ~
编辑: 此外,此页面还说派生表在联接发生之前已执行/实例化。为什么不重新使用键来执行联接?
4 j* S$ _* j1 v) }) h. X, Q3 t编辑2: MySQL# Z" j/ u, Q- j: E7 F: W" L
Optimizer不允许您在派生表上放置索引提示(大概是因为派生表上没有索引)
1 ?1 t+ F, o# k* m. {& q编辑3: 这是一个关于此的非常好的博客文章:http :9 M/ L9 x& t1 r9 M0 R4 ]: V2 F
//venublog.com/2010/03/06/how-to-improve-subqueries-derived-tables-2 ~; m8 T, K2 Q
performance/ 注意案例2是我的解决方案正在寻找,但MySQL目前不支持此功能。
0 [# S' N% j& a0 I编辑4: 刚刚发现这个:“在MySQL
" [! A% ?. K* H) p/ E. _5.6.3,优化更有效地处理子查询在FROM子句(即派生表):......在查询执行,优化程序可以添加一个索引来派生表加快从中进行行检索的速度。”/ ]! d0 W7 r& C. \6 b; x- `
似乎很有希望…
6 r: R- g& c# \7 B8 `  {( ?6 x0 [                * m! ]7 z! @8 ^  L
解决方案:4 O6 K2 s' {7 ^3 p7 R
               
, S% x! ^% C1 W9 E/ D) u( z9 B
" w- X9 X  ~! |9 C' S& ?6 I
0 g- X7 ?/ a. ^- d                在MySQL Server 5.6中,有一个解决方案-预览版(在撰写本文时)。  a, v  F9 K2 ]# N4 l# }
http://dev.mysql.com/doc/refman/5.6/en/from-clause-subquery-8 b9 z( z* u% c
optimization.html
& @! R0 s/ L+ ^8 ?1 b/ [虽然,我不确定在“将索引添加到派生表中”时MySQL Optimizer是否会重用已经存在的索引。% W8 C/ E. t# p3 E
考虑以下查询:# d7 ^  J; v5 t- j4 a/ e; R
SELECT * FROM t1 JOIN(SELECT * FROM t2)AS named_t2 ON t1.f1 = derived_t2.f1;& b. l, I' _0 e9 t! G  t
该文档说:“如果这样做可以允许对最低成本的执行计划使用ref访问,那么优化程序将在f1的f1列上构造一个索引。”0 _7 E; j4 p0 H5 K1 M
好的,那很好,但是优化程序会重用t2的索引吗?换句话说,如果存在针对t2.f1的索引该怎么办?该索引会被重用,还是优化程序为派生表重新创建该索引?谁知道?
7 c# X5 P' O& D* H+ J编辑: 直到MySQL 5.6,最好的解决方案是创建一个临时表,在该表上创建一个索引,然后在临时表上运行SELECT查询。
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则