同一个ORDER BY查询,只改sort_buffer_size,用Sort_merge_passes这个状态变量验证filesort到底什么时候会真的落盘。
5万行orders按amount降序排序,不走任何索引(amount上没有可用的排序索引时的路径),观察是否触发磁盘归并。
代码SET SESSION sort_buffer_size = <不同的值>; FLUSH STATUS; CREATE TEMPORARY TABLE sink AS SELECT customer_id, amount FROM orders ORDER BY amount DESC; SHOW SESSION STATUS LIKE 'Sort_merge_passes';
sort_buffer_size = 32768 (32KB): Sort_merge_passes = 6 耗时约110.3ms sort_buffer_size = 262144 (256KB,默认): Sort_merge_passes = 1 耗时约 77.0ms sort_buffer_size = 67108864 (64MB): Sort_merge_passes = 0 耗时约 75.2ms
Sort_merge_passes这个状态变量真实记录了排序过程中做了几次"外部归并"——当要排序的数据一次性装不进sort_buffer_size这块内存缓冲区时,MySQL会把数据分成若干块,每块在内存里排好序后写成一个临时文件,最后再对这些临时文件做归并,这个归并次数就是Sort_merge_passes。32KB缓冲区太小,5万行数据被切成很多小块,真实产生了6次归并;256KB(MySQL的默认值)也真实不够装下全部5万行,产生了1次归并;只有开到64MB,全部数据一次性能在内存里排完,归并次数才真实降到0。
每一步都是本文上面用SHOW STATUS跑出来的原始结果。
SESSION sort_buffer_size + SHOW STATUS LIKE 'Sort_merge_passes':判断排序是否真实触发磁盘归并