尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
SQL Server索引优化实战:从原理到碎片管理,告别慢查询
不少做开发的朋友一开始接触SQL Server写SQL查询、建表、导数据都能上手但一到SQL Server 索引这块就有点发怵。索引这个东西说简单也简单就是给表加个B树结构让查询不整表扫描说复杂也复杂聚集索引、非聚集索引、覆盖索引、过滤索引再加上索引碎片、统计信息、填充因子、列顺序这些细节一个没配好查询可能不升反降。我这些年遇到过不少生产事故——有因为缺索引导致一条查询跑了十几秒拖垮整个业务库的也有因为索引建多了每次写入都像背了个沙袋慢得离谱的还有因为索引碎片率飙到90%以上存储膨胀、IO打满的。这篇文章我就把这十来年折腾SQL Server索引的经验整理一下从原理到实操从建索引到查问题一次性讲透。不管你是刚入门的新手还是已经写过不少查询、想系统化理解索引的老手这篇都能给你点实在东西。1. 索引到底是什么为什么能提速1.1 没有索引时SQL Server怎么查数先想一个最简单的场景一张订单表有一千万行记录你执行一条SELECT * FROM orders WHERE customer_id 888888SQL Server怎么找到这一批订单在没有索引的情况下SQL Server只能做全表扫描Table Scan。意思是数据库把这张表的每一页、每一行从头到尾读一遍逐行判断customer_id是不是等于888888。一千万行如果每行只占100字节那也要扫差不多1GB的数据。如果这张表还在机械硬盘上一次查询几十秒很正常就算在SSD上这种扫描也是巨大浪费。这里有个容易误解的点全表扫描不是慢的代名词它的问题在于数据量和扫描时间严格成正比。表小全表扫描反而是最快的方案因为省去了走索引的额外IO表一大线性扫描的时间就不可接受了。1.2 索引就是数据库里的目录索引的本质就是给数据建立一套排好序的、体积小很多的查找结构。你可以把它理解成新华字典的拼音检字表——你不会一页一页翻字典找喆字而是先去拼音索引里找到zhe在哪一页然后直接翻到那一页。SQL Server里最常用的索引结构是B树Balanced Tree。这棵树的叶子节点保存着两种东西之一要么是表的实际数据行聚集索引要么是指向数据行的指针非聚集索引。内部节点则保存着索引键值和下一层节点的引用。当你根据索引键去查找时SQL Server会从B树的根节点出发一路二分查找经过四五层就可以定位到目标叶子页而不是扫描整张表。这个查找路径极短一个千万级的表B树可能也就四层所以一次索引查找只需要几次逻辑IO就能拿到数据。1.3 聚集索引和非聚集索引的核心差异这是理解SQL Server索引最关键的一步。**聚集索引Clustered Index**决定了表的物理存储顺序。一张表只能有一个聚集索引因为数据行只能有一种物理排列方式。你可以把它想象成书本身——每一页的内容就是按页号顺序装订的。在SQL Server里如果你给表建了主键约束系统默认会在这列上创建一个聚集索引除非表上有现成的聚集索引或你显式指定NONCLUSTERED。**非聚集索引Nonclustered Index**则是一个完全独立的、排好序的结构它不改变表数据本身的物理顺序而是记录了索引键值 → 数据行位置的映射。非聚集索引可以建很多个但每个都占用额外的存储空间而且每次INSERT、UPDATE、DELETE都要同步维护。我见过太多人把这两者搞混。记住下面这几点差异面试、调优都能用上对比项聚集索引非聚集索引数量限制每表仅1个每表最多999个实际不建议超过10个存储结构叶子节点存整行数据叶子节点存索引键 聚集索引键/行定位器物理顺序影响表数据物理顺序不影响表数据物理顺序插入性能对递增键友好对随机键可能产生页分裂每次写入都需要额外维护索引结构覆盖能力天然覆盖所有列只有索引键包含的列能覆盖这里有个非常容易踩的坑如果你在GUID列上建聚集索引插入时经常要挪动数据、分裂页面造成大量碎片。所以实战中主键如果是个毫无业务意义的自增int或bigint那它做聚集索引非常合适如果是GUID主键我宁可拿一个业务上的单调递增列做聚集索引或者专门加一个自增列。2. 索引类型盘点与选型思路2.1 主键索引、唯一索引、普通索引有什么区别很多初学者看到这个就懵了主键索引是聚集索引吗唯一索引和主键索引能同时建吗普通索引又是什么先理清楚主键和索引是两个维度的概念。主键是逻辑约束——保证一列或一组列的值不重复且不为空索引是物理结构——用来加速查找。主键约束在物理实现上一定要有索引支撑否则每次插入都要扫描全表去检查有没有重复。在SQL Server里你创建主键约束时默认会连带创建一个唯一索引默认聚集除非你显式CLUSTERED/NONCLUSTERED声明。唯一索引由于键值不重复在B树查找时能更快确定目标但唯一索引并不等同于主键——唯一索引允许一个NULL值SQL Server里一个唯一索引列可以有多个NULL但旧版本会有细节差异实际测试为准而主键列不允许为NULL。普通索引普通策略下系统为用户建立的通用索引没有唯一性约束纯粹为了加速查询。所以建索引之前你先问自己这条查询是等值查询还是范围查询查询条件经常一起出现吗要不要建联合索引查询需要返回的列能否完全覆盖这个表主要读多写少还是读少写多2.2 覆盖索引的威力与代价所谓覆盖索引是指查询所需的所有列都包含在非聚集索引的键列或包含列INCLUDE里。这种情况下SQL Server只需要读索引页就够了不需要再回表找数据行。举一个实战例子-- 假设表结构Orders(OrderID INT, CustomerID INT, OrderDate DATETIME, TotalAmount DECIMAL(18,2)) SELECT OrderID, OrderDate FROM Orders WHERE CustomerID 1001;如果只在CustomerID上建一个普通非聚集索引SQL Server走索引找到匹配的CustomerID后还要拿着OrderID去聚集索引里回表才能取到OrderDate。一来一回可能产生大量随机IO。改成覆盖索引CREATE NONCLUSTERED INDEX IX_Orders_CustomerID ON Orders(CustomerID) INCLUDE (OrderID, OrderDate);这时候查询要的所有列都在索引里SQL Server连回表都不用做直接在索引层面把结果拼出来。这种性能提升往往比单纯加索引键还明显。但代价是存储空间加倍写入时的维护开销也更大。所以覆盖索引只适合高频、热点、结果列固定的查询千万别为了省事把整张表所有列都放进去——那就不如建个聚集索引了。2.3 联合索引的列顺序怎么排联合索引Composite Index是最容易考人、也最影响性能的部分。核心原则其实就一句话最左前缀原则查询条件里必须包含联合索引最左边的列这个索引才有可能被用上。但列顺序还能进一步优化。一个我在生产环境总结出来的经验是等值条件的列放前面范围条件的列放后面高选择率区分度大的列放前面低选择率的列放后面如果都是等值条件把最常用来过滤的列放最前面。举例说明。表UserLogs(UserID INT, LogTime DATETIME, Action VARCHAR(50))最常见的查询是SELECT * FROM UserLogs WHERE UserID 999 AND LogTime BETWEEN 2025-01-01 AND 2025-02-01;那么联合索引(UserID, LogTime)是正确的——UserID做等值约束选列顺序时把等值条件的列放前面SQL Server能先精确缩小范围再在索引内做区间扫描。如果反过来建(LogTime, UserID)虽然理论上这个查询也能用上索引但B树先按时间排序时间范围筛完之后再找UserID扫描的叶子页数量会大很多。差距深究起来就是索引树前缀区分度的差距。2.4 过滤索引和包含列的适用场景过滤索引Filtered Index是SQL Server 2008之后提供的功能它允许你在建索引时加一个WHERE条件只对满足条件的行建索引。最典型的场景是表里大量行是软删除状态大多数查询都只关心未删除的数据。CREATE NONCLUSTERED INDEX IX_ActiveOrders ON Orders(CustomerID) INCLUDE (OrderID, OrderDate) WHERE Status 1;这个索引体积比全量索引小得多维护开销也低。但需要注意查询条件必须能准确匹配这个过滤条件否则索引不会被用到。包含列INCLUDE在上面已经说过它不参与索引键排序只放在叶子节点上做负载。它适合索引键无法覆盖、但只想减少回表的场景。记住一个关键点INCLUDE的列不会用于索引查找只用于覆盖查询结果列。3. 从零开始创建索引的完整实操3.1 建索引的前置分析先看执行计划再动手新手最常见的错误是上来就噼里啪啦建一堆索引看起来每个查询都用上了索引结果索引维护负担比查询收益还大。我的习惯是三步走抓慢查询sys.dm_exec_query_stats和sys.dm_exec_sql_text配合找出耗时最长、逻辑IO最高的SQL。看执行计划需要关注的实际行数、估计行数、明显的高IO操作符比如Key Lookup回表、RID Lookup、Table Scan、Index Scan。按需建索引缺索引时执行计划里经常会给你 Missing Index 提示参考它但不盲从。执行计划里出现Key Lookup往往说明这个非聚集索引还不够覆盖查询列需要用聚集索引键回表。这时候要么调整INCLUDE要么调整查询的返回列。SQL Server有一个很方便的动态管理视图专门给你提缺索引建议SELECT migs.avg_total_user_cost * migs.avg_user_impact * (migs.user_seeks migs.user_scans) AS improvement_measure, mid.statement AS table_name, mid.equality_columns, mid.inequality_columns, mid.included_columns FROM sys.dm_db_missing_index_group_stats AS migs INNER JOIN sys.dm_db_missing_index_groups AS mig ON migs.group_handle mig.index_group_handle INNER JOIN sys.dm_db_missing_index_details AS mid ON mig.index_handle mid.index_handle ORDER BY improvement_measure DESC;这条查询直接告诉你哪些表缺索引、建议等值列是什么、范围列是什么、建议包含列是什么。不过别拿它当圣旨它只是一个基于成本估算的建议最终还要结合业务实际。3.2 使用T-SQL创建索引语法与参数详解在实际生产库大部分时候我们是写T-SQL脚本去创建索引而不是在SSMS界面里点点点。脚本的好处是可版本化、可回滚、可评审。语法如下CREATE [ UNIQUE ] [ CLUSTERED | NONCLUSTERED ] INDEX index_name ON table_name ( column [ ASC | DESC ] [ ,...n ] ) [ INCLUDE ( column [ ,...n ] ) ] [ WHERE filter_predicate ] -- 过滤索引SQL Server 2008 [ WITH ( PAD_INDEX { ON | OFF }, FILLFACTOR fillfactor, SORT_IN_TEMPDB { ON | OFF }, IGNORE_DUP_KEY { ON | OFF }, STATISTICS_NORECOMPUTE { ON | OFF }, DROP_EXISTING { ON | OFF }, ONLINE { ON | OFF }, ALLOW_ROW_LOCKS { ON | OFF }, ALLOW_PAGE_LOCKS { ON | OFF }, MAXDOP max_degree_of_parallelism ) ] [ ON filegroup | ON partition_scheme ];几个重要参数说明FILLFACTOR填充因子表示索引页的初始填充百分比。默认0实际上相当于100%如果建索引时设为80则每页预留20%空间给后续插入可以减少页分裂但会增加索引体积。OLTP高写入场景推荐设70-85纯查询库设100。ONLINE ON在线创建索引不锁表允许DML并发。企业版支持标准版在新版本中也部分支持。大表上线前改索引基本都用在线方式。SORT_IN_TEMPDB ON排序中间结果放进tempdb能降低目标文件组的碎片但需要tempdb有足够空间。生产环境我一般开着但要注意tempdb本身别爆了。DROP_EXISTING ON重建索引替代先DROP再CREATE可以保持索引名和依赖关系不变。来看一个实际的完整案例。假设Orders表有2000万行CustomerID和OrderDate高频出现在查询条件里OrderID经常需要被SELECT返回CREATE NONCLUSTERED INDEX IX_Orders_CustomerID_OrderDate ON Orders(CustomerID, OrderDate) INCLUDE (OrderID) WITH ( ONLINE ON, FILLFACTOR 90, SORT_IN_TEMPDB ON );这里我给填充因子设置90是因为这张表在业务中间可想而知会有一定量的插入但又不至于像日志表那样频繁。90%既能减少页分裂又不会让索引文件大到离谱。ONLINE ON保证创建过程中业务还能继续写。3.3 用图形界面创建索引的路径有些运维同事习惯在SSMS里操作。流程是对象资源管理器 → 找到表 → 右键 → 设计 → 索引/键 → 添加或者直接右键索引→新建索引。SSMS里能设置索引名称、类型、键列、包含列、填充因子等。生产环境我仍然建议把脚本保存下来方便评审和后续在另外一台库上回放。UI操作和脚本不是二选一正确姿势是UI建完之后让SSMS生成脚本放到版本库里。4. 索引维护与性能监控实战4.1 索引碎片是怎样产生的索引碎片产生的主要原因是页分裂和页顺序错乱。当B树叶子页已经满了而你又插入了一条新记录尤其键值不在末尾SQL Server会把原本的页拆成两页新数据落到新页上这样物理上相邻的逻辑页就变少了。久而久之逻辑顺序和物理顺序不一致、页上空洞增多扫描索引时就需要更多IO。碎片率可以通过这个查询来查SELECT OBJECT_NAME(ps.OBJECT_ID) AS table_name, i.name AS index_name, ps.index_type_desc, ps.avg_fragmentation_in_percent, ps.page_count, ps.avg_page_space_used_in_percent, ps.record_count FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, LIMITED) AS ps INNER JOIN sys.indexes AS i ON ps.object_id i.object_id AND ps.index_id i.index_id WHERE ps.page_count 1000 ORDER BY ps.avg_fragmentation_in_percent DESC;这个查询会列出来当前数据库里所有索引的碎片率、页数、平均页面利用率。注意LIMITED模式很快不会扫描全部数据页如果你要更精确的结果可以用SAMPLED或DETAILED但大表上会比较耗资源。4.2 什么时候该重组、什么时候该重建这个不能一刀切我一般这么判断碎片率在 5%~30% 之间采用ALTER INDEX ... REORGANIZE。这个操作轻量相当于整理页面顺序不重建整个索引。碎片率超过30%采用ALTER INDEX ... REBUILD相当于把索引从头建一遍能彻底消除碎片。大表建议用ONLINE ON。还有一种情况碎片率不高但avg_page_space_used_in_percent很低比如低于70%说明页内部空间浪费严重也需要重建。实际执行脚本-- 重组 ALTER INDEX IX_Orders_CustomerID_OrderDate ON dbo.Orders REORGANIZE; -- 重建在线 ALTER INDEX IX_Orders_CustomerID_OrderDate ON dbo.Orders REBUILD WITH (ONLINE ON);如果表上所有索引都需要重建可以直接对表执行ALTER TABLE dbo.Orders REBUILD WITH (ONLINE ON);在日常维护计划里我建议给索引维护建立一个单独的作业。频率取决于你的写入频率像订单库这种每天都大量写入的表我一般每周重组一次、每月重建一次像配置表那种几乎不写入的根本不需要定期维护一年一次意思意思就够了。4.3 统计信息过期比索引碎片更致命很多DBA只盯着碎片率却忽略了统计信息。统计信息是SQL Server用来估算行数的依据索引该不该用、用哪个索引全靠它。统计信息过期执行计划就会走偏明明有索引却不走或者超低效的嵌套循环。默认情况下SQL Server会自动更新统计信息但自动更新的阈值是表行数变化超过20%左右才触发。对于大表20%可能是几十万行中间这段时间就可能有糟糕的执行计划。检查统计信息更新时间的查询SELECT s.name AS stats_name, object_name(s.object_id) AS table_name, sp.last_updated, sp.rows_sampled, sp.rows, sp.modification_counter FROM sys.stats AS s CROSS APPLY sys.dm_db_stats_properties(s.object_id, s.stats_id) AS sp ORDER BY sp.last_updated ASC;如果发现某些高频表统计信息很久没更新可以手动更新UPDATE STATISTICS dbo.Orders IX_Orders_CustomerID_OrderDate WITH FULLSCAN;注意WITH FULLSCAN会扫描全表数据量大的时候很耗费IO建议放在业务低峰期执行。小表和关键热点表用FULLSCAN超大表可以用SAMPLE 10 PERCENT之类速度和准确度之间取个平衡。4.4 监控谁在等索引、谁在用索引索引建了到底用没用不用的话就是白吃存储和写入开销。可以用下面两条DMV来排查查询索引使用情况SELECT OBJECT_NAME(s.object_id) AS table_name, i.name AS index_name, i.type_desc, s.user_seeks, s.user_scans, s.user_lookups, s.user_updates FROM sys.dm_db_index_usage_stats AS s INNER JOIN sys.indexes AS i ON s.object_id i.object_id AND s.index_id i.index_id WHERE s.database_id DB_ID() ORDER BY (s.user_seeks s.user_scans s.user_lookups) ASC;user_seeks多说明这个索引在帮等值/范围查询获取数据user_scans多说明SQL Server在执行计划里做了全索引扫描这就得仔细分析是不是索引设计不合理了user_updates很大但查询几乎不用这个索引该考虑删除。还有一个很好用的DMV——sys.dm_db_index_operational_stats能看到等待类型、闩锁等待、页面拆分次数等等排查热点索引时很有用。5. 常见问题与排查技巧实录5.1 索引没走先检查这五个原因明明建了索引执行计划却显示Table Scan或Index Scan我遇到过的原因按概率从高到低排一下统计信息过期SQL Server估算目标行数占比太高觉得走索引还不如全扫。更新统计信息再看。查询写法导致索引失效对索引列做了函数运算比如WHERE YEAR(OrderDate) 2025这时索引键列被函数包裹无法用常规索引查找。解决改成WHERE OrderDate 2025-01-01 AND OrderDate 2026-01-01。数据类型隐式转换索引列是varchar查询参数传了nvarchar或者反过来SQL Server必须做隐式转换索引就废了。我之前排查过一个实际问题就是WHERE Phone phone列是varchar(20)参数却是nvarchar(50)执行计划里出现CONVERT_IMPLICIT整条查询全表扫了七千万行。联合索引最左前缀不满足索引是(A, B)但查询条件只写了B。选择性太低列上全是重复值SQL Server优化器觉得走索引也没意义。其中第3条最阴排查的时候一定要去看执行计划里有没有CONVERT_IMPLICIT这个关键字。我建议统一约定表字段和参数都用nvarchar或都用varchar尽量不要混用。5.2 索引也分好碎片和坏碎片这里我想纠正一个常见的极端做法有人看到碎片率超过30%就立即重建。碎片率和查询性能之间的关系并不是线性的有些索引碎片率50%但查询照样快因为数据量小、页数少反过来一个页数上百万的大索引即使碎片率20%扫描起来也很疼。另外页分裂并不完全是坏事。如果业务写入的键值本身就是随机的比如GUID分裂后反而可能让数据分布更均匀。真正需要密切关注的是逻辑碎片和页密度。页密度低说明每页存的行数少同样的行数占的页更多IO次数自然上升。我给自己定过一套大致的维护策略供参考表类型写入频率维护策略日志流水表极高频尽量使用顺序键定期归档旧数据索引只保留必要的一两个业务交易表高频联合索引/覆盖索引设计每周重组每月重建配置字典表极低频建索引后基本不管统计信息更新即可报表历史表批量导入导入前禁用索引导完再重建效率能差10倍以上5.3 删除和禁用索引的注意事项在整理索引时发现无用索引要果断删。但删除之前一定要注意下面几件事先确认这个索引是不是某个约束主键、唯一约束在支持如果是直接DROP INDEX会报错你得先删约束或用ALTER TABLE DROP CONSTRAINT。检查是否有计划和作业引用了这个索引名。有些脚本里写了WITH (INDEX(IX_XXX))提示索引一删查询直接报错。删除大表的索引非常耗时会持有锁一定要安排在维护窗口。不要今天删了明天发现不行又建回来。删除前我通常先禁用索引ALTER INDEX ... DISABLE观察几天确认没有查询变慢再彻底DROP。禁用索引后查询不会用到它但索引结构还在随时可以重建启用。-- 禁用索引保留定义不影响查询使用 ALTER INDEX IX_Orders_CustomerID_OrderDate ON dbo.Orders DISABLE; -- 确认稳定后删除 DROP INDEX IX_Orders_CustomerID_OrderDate ON dbo.Orders; -- 临时重建 ALTER INDEX IX_Orders_CustomerID_OrderDate ON dbo.Orders REBUILD;这种方式虽然多占用一点空间但对于生产环境来说安全性远高于直接删。5.4 一个典型的慢查询排查案例曾经处理过一个真实案例某系统有个报表查询每天晚上跑1个小时直接拖垮其他业务。表有3800万行查询脚本长这样SELECT CustomerID, SUM(Amount) FROM Orders WHERE OrderDate 2025-01-01 AND OrderDate 2025-02-01 GROUP BY CustomerID;当时表上只有一个主键聚集索引OrderIDOrderDate上没有索引所以这个查询必然走全表扫描。3800万行GROUP BY还要排序不慢才怪。我当时没有直接建索引先跑了一下sys.dm_db_missing_index_details看到的建议是在OrderDate上建等值索引并建议单独加CustomerID作为包含列。我看了一眼查询等值条件是OrderDate范围分组列是CustomerIDSUM的是Amount。于是建了这样一个覆盖索引CREATE NONCLUSTERED INDEX IX_Orders_OrderDate_CustomerID ON Orders(OrderDate, CustomerID) INCLUDE (Amount);为什么把CustomerID放在索引键里而不是INCLUDE因为GROUP BY CustomerID可以利用索引的有序性做流聚合省掉中间排序。Amount用INCLUDE是因为它不需要参与查找和排序只是取值计算。重建索引之后这个查询从1小时降到不足5秒。后来我发现这个报表只查最近三个月数据又把索引改成过滤索引CREATE NONCLUSTERED INDEX IX_Orders_OrderDate_CustomerID_Active ON Orders(OrderDate, CustomerID) INCLUDE (Amount) WHERE OrderDate 2025-01-01;索引体积进一步缩小。注意这里的过滤条件要和查询完全匹配否则走不了。这也是为什么很多老DBA不推荐过度使用过滤索引的原因——过滤索引的匹配规则比较严格用不好反而坑人。5.5 生产环境改索引的七个建议如果上面那些内容对你来说都理解了最后送你几个我在生产环境摸爬滚打总结出来的建议变更前备份就算只改索引也建议先把相关表的定义和依赖脚本导出保存。用ONLINE重建能有效避免长时间锁表但要注意日志文件和tempdb的空间是否足够。分批次做别一次性重建或创建几百个索引先做核心表的做完观察一段时间再说。低峰期执行REBUILD期间即使在线也会增加日志量和IO压力。通知监控系统变更完记得检查慢查询监控是否正常。在变更脚本里加SET XACT_ABORT ON万一中途失败自动回滚避免半截索引。记录索引变更日志谁在什么时候加了哪个索引、为什么加以后排查起来事半功倍。关于MONITOR、索引的碎片维护和统计信息更新比拼的其实是你是否了解你的业务。索引没有放之四海而皆准的固定配置必须回到具体查询、具体表的写入频率、具体数据分布来选择。我这些年最深的体会就是索引设计是数据库性能优化里投入产出比最高的一环一个合理的索引能让查询从惨不忍睹变成直接起飞而一个多余的索引也能让写入从顺畅变成便秘。多用执行计划和DMV去验证你的判断少靠猜性能问题都会找到根源。最后再分享一个小技巧每次建完索引养成习惯去跑一遍DBCC SHOW_STATISTICS看看统计信息内容确认采样行数和密度分布正常再跑一遍实际查询的执行计划确认它真的用了你新建的索引。眼见为实这比任何按理说应该走索引都靠谱。
RELATED

相关推荐

U盘文件夹突然消失?.scr病毒隐藏文件恢复与清除全攻略

U盘文件夹突然消失?.scr病毒隐藏文件恢复与清除全攻略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/9/13 10:19:40
2026智能体数据库代理选型:OpenClaw架构下的PolarDB、ArkClaw与DatabaseClaw深度对比

2026智能体数据库代理选型:OpenClaw架构下的PolarDB、ArkClaw与DatabaseClaw深度对比

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/9/13 10:19:40
Elasticsearch底层原理详解:索引、分片、选举与脑裂防护

Elasticsearch底层原理详解:索引、分片、选举与脑裂防护

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/9/13 10:19:40
MORE NEWS

更多资讯

📰

RIAV-MVS:不对称体积与循环索引实现高效多视图立体匹配

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

C++在实时操作系统中的高效实践与优化技巧

1. 实时操作系统与C的化学反应我第一次在VxWorks上尝试用C开发实时控制程序时,意外发现这个组合比想象中更强大。传统观念认为实时系统应该用C语言开发,但现代C的特性正在改变这一格局。实时操作系统(RTOS)对时间确定性有严苛要求…

📰

Backstage v1.6.0 版本深度解读:React Router v6 兼容、CLI 现代化与搜索能力全面增强

Backstage v1.6.0 版本深度解读:React Router v6 兼容、CLI 现代化与搜索能力全面增强 【免费下载链接】backstage Backstage is an open framework for building developer portals 项目地址: https://gitcode.com/GitHub_Trending/ba/backstage 导读 Back…

📰

Xiaomi Home Integration for Home Assistant 深度指南:从云端/本地控制架构到 MIoT-Spec-V2 实体映射

Xiaomi Home Integration for Home Assistant 深度指南:从云端/本地控制架构到 MIoT-Spec-V2 实体映射 【免费下载链接】ha_xiaomi_home Xiaomi Home Integration for Home Assistant 项目地址: https://gitcode.com/GitHub_Trending/ha/ha_xiaomi_home Xiao…

📰

大模型选型不是比参数,而是比工程契约

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

自动驾驶路径跟踪的MPC控制与MATLAB实现

1. 自动驾驶路径跟踪的核心挑战与解决方案 在自动驾驶技术快速发展的今天,路径跟踪作为车辆控制系统的关键环节,直接决定了行驶的平顺性和安全性。传统PID控制器在简单场景下表现尚可,但当面对复杂道路条件、高速行驶或突发干扰时&#xff0c…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬