首页 关于我们 成功案例 网络营销 电商设计 新闻中心 联系方式
QQ联系
电话联系
手机联系

覆盖索引与索引条件下推(ICP)技术详解与性能提升

发布时间:2025-09-10 10:28
发布者:网络
浏览次数:
<blockquote>覆盖索引和ICP通过减少I/O与数据传输提升查询性能,前者避免回表,后者在存储引擎层提前过滤,结合使用可显著优化查询效率。</blockquote> <p><img src="https://img.php.cn/upload/article/001/253/068/175747128246778.jpeg" alt="覆盖索引与索引条件下推(icp)技术详解与性能提升"></p> <p>数据库性能优化,特别是面对高并发和<a style="color:#f60; text-decoration:underline;" title="大数据" href="https://www.php.cn/zt/16141.html" target="_blank">大数据</a>量时,往往不是一蹴而就的。覆盖索引(Covering Index)和索引条件下推(Index Condition Pushdown, ICP)这两项技术,在我看来,就是数据库优化<a style="color:#f60; text-decoration:underline;" title="工具" href="https://www.php.cn/zt/16887.html" target="_blank">工具</a>箱里不可或缺的两把利器。它们的核心目标都是为了减少数据库在处理查询时的数据传输量和计算量,从而显著提升查询效率。简单来说,覆盖索引让数据库只通过索引就能获取到所有需要的数据,避免了回表操作;而ICP则是在存储引擎层面就对索引数据进行过滤,减少了传递给服务器层的数据量。</p> <h3>解决方案</h3> <p>在深入理解这两项技术之前,我们先从它们各自的工作原理和优势入手。</p> <p><strong>覆盖索引(Covering Index)</strong></p> <p>想象一下,你想要从一本书里找到某个章节的标题和页码。如果你手头有这本书的目录(索引),并且目录里已经包含了你所需的所有信息(标题和页码),你就不需要翻阅到具体的章节内容(回表)就能得到答案。这就是覆盖索引的直观体现。</p> <p>在数据库中,当一个查询所需的所有列(包括<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">SELECT</pre></div>列表中的列和<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">WHERE</pre></div>子句中的条件列)都可以在某个索引中找到时,这个索引就被称为覆盖索引。数据库存储引擎在执行查询时,只需要扫描这个索引,而无需再访问实际的数据行(表)。</p> <ul> <li> <strong>工作原理:</strong><ol> <li>数据库接收到一个查询请求。</li> <li>优化器识别出存在一个索引,其包含查询所需的所有列。</li> <li>存储引擎直接从该索引中读取数据并返回,完全避免了对数据表的访问。</li> </ol> </li> <li> <strong>核心优势:</strong><ul> <li> <strong>减少磁盘I/O:</strong> 这是最显著的优势。因为不需要回表,减少了随机I/O,甚至可能将随机I/O变为顺序I/O(如果索引是聚簇索引或二级索引的叶子节点)。</li> <li> <strong>减少CPU开销:</strong> 避免了根据主键或行指针去查找数据行的额外操作。</li> <li> <strong>提高查询速度:</strong> 尤其对于读密集型应用,性能提升非常明显。</li> </ul> </li> </ul> <p><strong>索引条件下推(Index Condition Pushdown, ICP)</strong></p> <p>ICP则是一种更“精细化”的优化,它关注的是在数据从存储引擎传递到服务器层之前,尽可能多地进行过滤。这就像你在图书馆找书,管理员在给你拿书之前,就帮你筛选掉了不符合你额外条件(比如出版年份)的书,而不是把所有符合主要条件(比如作者)的书都拿给你,再让你自己去筛选。</p> <p>在MySQL 5.6及更高版本中引入的ICP,允许存储引擎(如InnoDB)在遍历索引时,就对<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">WHERE</pre></div>子句中的部分条件进行评估和过滤。</p> <ul> <li> <strong>工作原理:</strong><ol> <li>当查询使用二级索引进行查找时,存储引擎会先根据索引的前缀部分进行定位。</li> <li>如果<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">WHERE</pre></div>子句中还有其他条件,并且这些条件涉及的列也包含在当前索引中(即使不是索引的前缀部分),存储引擎会在将完整的索引行传递给服务器层之前,先对这些条件进行评估。</li> <li>只有那些通过了所有下推条件的索引行,才会被发送到服务器层进行后续处理(比如回表获取完整行数据)。</li> </ol> </li> <li> <strong>核心优势:</strong><ul> <li> <strong>减少存储引擎与服务器层之间的数据传输量:</strong> 避免了传输不必要的数据,节省了网络带宽和CPU周期。</li> <li> <strong>减少回表操作:</strong> 虽然ICP本身不直接避免回表,但通过更早的过滤,可以减少需要回表的行数。</li> <li> <strong>提高复合索引的利用率:</strong> 对于那些复合索引中非前缀部分的条件,ICP能让它们在存储引擎层发挥作用。</li> </ul> </li> </ul> <p>这两项技术并非互斥,而是可以协同工作的。一个设计良好的索引,既可以作为覆盖索引避免回表,又可以通过ICP在索引扫描阶段就过滤掉大量不符合条件的记录,从而实现性能的最大化。</p> <h3>如何判断我的查询是否正在利用覆盖索引或ICP?</h3> <p>要理解数据库的实际执行计划,<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">EXPLAIN</pre></div>命令是你的黄金标准。它能揭示查询是如何被优化的,以及是否用到了覆盖索引和ICP。</p> <p>当你执行<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">EXPLAIN</pre></div>命令时,需要重点关注输出结果中的几个关键列:</p> <ol> <li> <p><strong><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">type</pre></div> 列:</strong></p> <ul> <li>如果显示 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">const</pre></div>、<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">eq_ref</pre></div>、<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">ref</pre></div>、<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">range</pre></div> 等,通常表示索引被有效利用。</li> <li><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">index</pre></div> 表示全索引扫描,虽然比全表扫描(<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">ALL</pre></div>)好,但如果能进一步优化成范围扫描会更好。</li> </ul> </li> <li> <p><strong><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">Extra</pre></div> 列:</strong> 这是判断覆盖索引和ICP的关键。</p> <ul> <li> <strong><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">Using index</pre></div>:</strong> 这是覆盖索引的明确信号。这意味着查询所需的所有数据都可以在索引中找到,数据库完全没有访问数据表。你的查询非常高效。</li> <li> <strong><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">Using index condition</pre></div>:</strong> 这表示索引条件下推(ICP)正在发挥作用。存储引擎在将索引行传递给服务器层之前,已经根据<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">WHERE</pre></div>子句中的条件进行了过滤。这通常出现在复合索引上,<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">WHERE</pre></div>条件涉及索引中的非前缀列。</li> <li> <strong><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">Using index; Using where</pre></div>:</strong> 这可能意味着索引是覆盖索引,但<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">WHERE</pre></div>子句中的条件不能完全由索引处理(比如有复杂函数),或者虽然条件列都在索引中,但优化器认为在服务器层处理更优。但核心是<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">Using index</pre></div>,说明仍然是覆盖索引。</li> <li> <strong><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">Using where</pre></div>:</strong> 如果只出现<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">Using where</pre></div>而没有<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">Using index</pre></div>,通常意味着需要回表,并且<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">WHERE</pre></div>条件是在服务器层处理的。</li> </ul> </li> </ol> <p><strong>实际例子:</strong></p> <p>假设我们有一个<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">users</pre></div>表,结构为 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">(id INT PRIMARY KEY, name VARCHAR(100), age INT, city VARCHAR(100))</pre></div>,并且有一个复合索引 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">idx_name_age_city</pre></div> 在 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">(name, age, city)</pre></div> 上。</p> <ul> <li> <p><strong>查询1(利用覆盖索引):</strong></p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:sql;toolbar:false;'>EXPLAIN SELECT name, age FROM users WHERE name = 'Alice';</pre></div><p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">Extra</pre></div> 列可能显示 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">Using index</pre></div>。因为 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">name</pre></div> 和 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">age</pre></div> 都在 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">idx_name_age_city</pre></div> 索引中,且 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">name</pre></div> 是索引前缀,所以可以直接从索引中获取所有需要的数据。</p> </li> <li> <p><strong>查询2(利用覆盖索引和ICP):</strong></p> <div class="aritcle_card"> <a class="aritcle_card_img" href="/ai/1626"> <img src="https://img.php.cn/upload/ai_manual/000/000/000/175680270981990.jpg" alt="FashionLabs"> </a> <div class="aritcle_card_info"> <a href="/ai/1626">FashionLabs</a> <p>AI服装模特、商品图,可商用,低价提升销量神器</p> <div class=""> <img src="/static/images/card_xiazai.png" alt="FashionLabs"> <span>86</span> </div> </div> <a href="/ai/1626" class="aritcle_card_btn"> <span>查看详情</span> <img src="/static/images/cardxiayige-3.png" alt="FashionLabs"> </a> </div> <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:sql;toolbar:false;'>EXPLAIN SELECT name, age, city FROM users WHERE name LIKE 'A%' AND age > 20 AND city = 'New York';</pre></div><p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">Extra</pre></div> 列可能显示 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">Using index condition</pre></div> 和 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">Using index</pre></div>。</p> <ul> <li><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">name LIKE 'A%'</pre></div> 会使用索引的前缀进行范围扫描。</li> <li><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">age > 20</pre></div> 和 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">city = 'New York'</pre></div> 这两个条件,因为 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">age</pre></div> 和 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">city</pre></div> 都在索引中,可以被ICP下推到存储引擎层进行过滤。</li> <li>同时,<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">SELECT</pre></div> 的 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">name, age, city</pre></div> 也都包含在索引中,所以也是覆盖索引。</li> </ul> </li> </ul> <p>通过<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">EXPLAIN</pre></div>,你就能清晰地看到数据库的“内心戏”,判断你的索引设计是否达到了预期的优化效果。如果发现没有利用到这些优化,那么就是时候重新审视你的索引策略了。</p> <h3>索引条件下推(ICP)在哪些场景下能发挥最大效用?</h3> <p>ICP并非万能,它在特定场景下能带来显著的性能提升。理解这些场景,有助于我们更好地设计索引和编写查询。</p> <ol> <li> <p><strong>复合索引(Multi-column Indexes)与非前缀条件结合时:</strong> 这是ICP最典型的应用场景。当你的<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">WHERE</pre></div>子句中包含复合索引中的多个列,但这些条件不能完全利用索引的前缀进行高效扫描时,ICP就能派上用场。 例如,有一个索引 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">(col1, col2, col3)</pre></div>。查询条件是 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">WHERE col1 = 'A' AND col3 = 'B'</pre></div>。</p> <ul> <li><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">col1 = 'A'</pre></div> 可以利用索引前缀进行查找。</li> <li><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">col3 = 'B'</pre></div> 无法直接利用索引进行查找(因为它不是<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">col1</pre></div>之后的连续前缀)。</li> <li>没有ICP时,所有 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">col1 = 'A'</pre></div> 的行都会被取出,然后服务器层再根据 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">col3 = 'B'</pre></div> 进行过滤。</li> <li>有了ICP,存储引擎在扫描 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">col1 = 'A'</pre></div> 的索引条目时,会同时检查 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">col3 = 'B'</pre></div> 的条件,只将符合条件的索引条目传给服务器层,大大减少了数据传输量。</li> </ul> </li> <li> <p><strong>范围查询(Range Scans)与附加过滤条件:</strong> 当索引被用于范围查询(如 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">></pre></div>、<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;"><</pre></div>、<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">BETWEEN</pre></div>、<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">LIKE 'prefix%'</pre></div>)时,如果<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">WHERE</pre></div>子句中还有其他条件,并且这些条件涉及的列也在该索引中,ICP可以提前过滤。 例如,索引 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">(order_date, status)</pre></div>。查询 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">WHERE order_date > '2025-01-01' AND status = 'completed'</pre></div>。</p> <ul> <li><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">order_date > '2025-01-01'</pre></div> 会进行索引范围扫描。<;/li> <li><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">status = 'completed'</pre></div> 可以在ICP的帮助下,在存储引擎层面就过滤掉不符合条件的记录。</li> </ul> </li> <li> <p><strong><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">LIKE</pre></div> 操作符:</strong> 特别是当<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">LIKE</pre></div>模式不是以通配符开头时(例如 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">LIKE 'abc%'</pre></div>),索引可以被利用。如果<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">WHERE</pre></div>子句中还有其他条件,并且这些条件涉及的列也在该索引中,ICP可以进一步优化。 例如,索引 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">(product_name, category)</pre></div>。查询 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">WHERE product_name LIKE 'Laptop%' AND category = 'Electronics'</pre></div>。</p> <ul> <li><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">product_name LIKE 'Laptop%'</pre></div> 使用索引进行范围扫描。</li> <li><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">category = 'Electronics'</pre></div> 可以通过ICP在存储引擎层进行过滤。</li> </ul> </li> <li><p><strong>大数据集和高选择性过滤:</strong> 当查询涉及的数据量非常大,并且ICP能够过滤掉大部分不符合条件的记录时,它的效果最为明显。因为过滤得越早,传输和处理的数据就越少,性能提升就越显著。</p></li> <li><p><strong>减少回表操作的潜在效益:</strong> 虽然ICP本身不直接避免回表,但通过在索引扫描阶段就过滤掉大量不符合条件的记录,可以显著减少最终需要回表获取完整行数据的次数,间接提升了性能。</p></li> </ol> <p>ICP的价值在于它让数据库的“内部工作”更加高效。它不是一个你需要显式去“开启”的功能,而是通过合理地设计索引和编写查询,让优化器有机会去利用它。</p> <h3>结合实际案例,如何设计索引以同时利用覆盖索引和ICP?</h3> <p>设计一个既能利用覆盖索引又能利用ICP的索引,需要对查询模式有深入的理解。这通常涉及到在复合索引中合理安<a style="color:#f60; text-decoration:underline;" title="排列" href="https://www.php.cn/zt/56129.html" target="_blank">排列</a>的顺序,并确保查询所需的所有列都在索引中。</p> <p>让我们以一个常见的电商场景为例:<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">orders</pre></div> 表,记录了用户的订单信息。</p> <p><strong><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">orders</pre></div> 表结构示例:</strong></p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:sql;toolbar:false;'>CREATE TABLE orders ( order_id INT PRIMARY KEY AUTO_INCREMENT, customer_id INT NOT NULL, order_date DATETIME NOT NULL, status VARCHAR(50) NOT NULL, -- e.g., 'pending', 'completed', 'shipped', 'cancelled' amount DECIMAL(10, 2) NOT NULL, product_name VARCHAR(255), shipping_address VARCHAR(500), INDEX idx_customer_date (customer_id, order_date) );</pre></div><p><strong>业务场景与查询需求:</strong> 我们经常需要查询某个客户在特定日期范围内的“已完成”订单,并显示订单ID、订单日期和金额。</p> <p><strong>查询示例:</strong></p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:sql;toolbar:false;'>SELECT order_id, order_date, amount FROM orders WHERE customer_id = 1001 AND order_date BETWEEN '2025-01-01' AND '2025-12-31' AND status = 'completed';</pre></div><p><strong>索引设计思路:</strong></p> <ol> <li> <p><strong>分析 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">WHERE</pre></div> 子句:</strong></p> <ul> <li><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">customer_id = 1001</pre></div>:这是一个等值查询,非常适合作为复合索引的第一个列,用于快速定位。</li> <li><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">order_date BETWEEN '2025-01-01' AND '2025-12-31'</pre></div>:这是一个范围查询,适合放在 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">customer_id</pre></div> 之后。</li> <li><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">status = 'completed'</pre></div>:这也是一个等值过滤条件。</li> </ul> </li> <li> <p><strong>分析 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">SELECT</pre></div> 列表:</strong></p> <ul> <li><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">order_id</pre></div>:这是主键,通常在二级索引的叶子节点中隐式存储,因此可以被“覆盖”。</li> <li><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">order_date</pre></div>:已在 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">WHERE</pre></div> 子句中,也需要被选中。</li> <li><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">amount</pre></div>:需要被选中。</li> </ul> </li> <li> <p><strong>构建索引:</strong> 基于上述分析,我们可以设计一个复合索引 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">idx_customer_date_status_amount</pre></div>:</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:sql;toolbar:false;'>CREATE INDEX idx_customer_date_status_amount ON orders (customer_id, order_date, status, amount);</pre></div></li> </ol> <p><strong>这个索引如何同时利用覆盖索引和ICP?</strong></p> <ul> <li> <p><strong>利用覆盖索引:</strong></p> <ul><li><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">SELECT</pre></div> 列表中的 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">order_id</pre></div> (PK), <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">order_date</pre></div>, <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">amount</pre></div> 都可以在这个索引中找到。<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">order_date</pre></div> 和 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">amount</pre></div> 是显式包含的。<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">order_id</pre></div> 作为主键,虽然没有显式列出在索引定义中,但MySQL的二级索引通常会隐式存储主键值,以便进行回表操作。但如果所有查询所需的数据(包括主键)都能从索引中获取,它仍然可以被认为是覆盖索引,避免了额外的数据页读取。</li></ul> </li> <li> <p><strong>利用ICP:</strong></p> <ul> <li><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">customer_id = 1001</pre></div>:用于索引的第一个列,进行精确查找。</li> <li><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">order_date BETWEEN '2025-01-01' AND '2025-12-31'</pre></div>:利用索引的第二个列进行范围扫描。</li> <li><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">status = 'completed'</pre></div>:这个条件涉及索引中的第三个列。在没有ICP的情况下,数据库可能会在扫描 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">customer_id</pre></div> 和 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">order_date</pre></div> 范围内的所有索引条目后,再将这些条目传递给服务器层,由服务器层来过滤 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">status</pre></div>。有了ICP,存储引擎在遍历索引时,就会直接检查 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">status = 'completed'</pre></div> 这个条件,只有符合条件的索引条目才会被传递到上层,从而减少了存储引擎和服务器层之间的数据传输。</li> </ul> </li> </ul> <p><strong><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">EXPLAIN</pre></div> 结果预测:</strong> 对上述查询执行 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">EXPLAIN</pre></div>,你很可能会在 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">Extra</pre></div> 列中看到 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false;">Using index condition; Using index</pre></div>。这明确表示了查询同时利用了ICP和覆盖索引。</p> <p><strong>总结:</strong></p> <p>在设计索引时,我的经验是:</p> <ol><li>**将等值条件列放在</li></ol>

以上就是覆盖索引与索引条件下推(ICP)技术详解与性能提升的详细内容,更多请关注其它相关文章!


# mysql教程  # mysql  # go  # 大数据  # 工具  # ai  # 排列  # 离线  # 这是  # 句中  # 所需  # 不符合  # 都在  # 就能  # 主键  # 会在  # 操作流程  # 钟祥seo推广公司  # 西安网站建设高端设计  # 深圳搜索引擎关键词排名  # 快三竞猜网站建设  # 过年如何营销推广产品  # 浙江创新seo优化  # 蒙牛网站建设推广  # 大良网站建设工作推荐  # 柳州关键词排名合作方式  # 网络营销有必要推广吗