文件排序而不是索引扫描
Posted
技术标签:
【中文标题】文件排序而不是索引扫描【英文标题】:Filesort instead of index scan 【发布时间】:2020-11-23 15:18:35 【问题描述】:我将我的 php/mysql 数据库从 Unix 迁移到 Windows。我转储了数据库并将其直接导入到 Windows 上,没有任何区别。我使用相同的脚本/PHP 版本。
我的桌子是:
CREATE TABLE `pximg` (
`ppoc` tinyint unsigned NOT NULL,
`file` int unsigned NOT NULL,
`ts` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`img` mediumblob,
PRIMARY KEY (`ppoc`,`file`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
我要重现的 PHP 脚本:
// SQL queries
$queryNoBindings = "EXPLAIN SELECT img, ts FROM pximg WHERE ppoc = 0 ORDER BY `file` DESC LIMIT 1";
$queryBindings = "EXPLAIN SELECT img, ts FROM pximg WHERE ppoc = ? ORDER BY `file` DESC LIMIT 1";
$ppoc = 0;
// connect
$m = new mysqli('127.0.0.1', $dbData['px'][1], $dbData['px'][2], $dbData['px'][3], $dbData['px'][4]);
// query with no bindings
$q = $m->query($queryNoBindings);
$r1 = $q->fetch_array(MYSQLI_ASSOC);
print_r($r1);
// query with bindings
$stmt = $m->prepare($queryBindings);
$stmt->bind_param('i', $ppoc);
$stmt->execute();
$r = $stmt->get_result();
$r2 = $r->fetch_array(MYSQLI_ASSOC);
print_r($r2);
Unix 上的结果是
Array
(
[id] => 1
[select_type] => SIMPLE
[table] => pximg
[partitions] =>
[type] => ref
[possible_keys] => PRIMARY
[key] => PRIMARY
[key_len] => 1
[ref] => const
[rows] => 385758
[filtered] => 100.00
[Extra] => Backward index scan
)
Array
(
[id] => 1
[select_type] => SIMPLE
[table] => pximg
[partitions] =>
[type] => ref
[possible_keys] => PRIMARY
[key] => PRIMARY
[key_len] => 1
[ref] => const
[rows] => 385758
[filtered] => 100
[Extra] => Backward index scan
)
Windows 上的结果是
Array
(
[id] => 1
[select_type] => SIMPLE
[table] => pximg
[partitions] =>
[type] => ref
[possible_keys] => PRIMARY
[key] => PRIMARY
[key_len] => 1
[ref] => const
[rows] => 370682
[filtered] => 100.00
[Extra] => Backward index scan
)
Array
(
[id] => 1
[select_type] => SIMPLE
[table] => pximg
[partitions] =>
[type] => ref
[possible_keys] => PRIMARY
[key] => PRIMARY
[key_len] => 1
[ref] => const
[rows] => 370682
[filtered] => 100
[Extra] => Using filesort
)
所以区别在于:当我在 Windows 上使用带有绑定的查询时,它现在使用的是文件排序而不是反向索引扫描,并且需要大约 20 秒而不是 0.02 秒。
有人知道为什么吗? 或者,如果文件排序没问题,为什么现在查询速度如此之慢?
【问题讨论】:
相同版本的 MySQL?案例请提供EXPLAIN FORMAT=JSON SELECT
。 “成本”可能略有不同。另请提供SHOW INDEXES FROM ..
——基数估计可能存在差异。
【参考方案1】:
您新加载的服务器似乎没有使用您的主键。
这里有一些事情可以尝试:
-
new 服务器上的
SHOW TABLE piximg;
向您显示批量加载表的定义。主键定义是否进入您的新表?如果没有,请执行此操作。
ALTER TABLE piximg ADD PRIMARY KEY(`ppoc`, `file`);
ALTER TABLE pximg ENABLE KEYS;
表示您的批量加载操作禁用了密钥处理。
OPTIMIZE TABLE pximg;
因为有时新批量加载的表的索引统计信息在优化之前没有意义。
针对此查询的具体情况,稍微更改索引定义,在file
列中包含DESC
限定符。
PRIMARY KEY (`ppoc`, `file` DESC)
模式SELECT blah, blah, blob ... ORDER BY blah DESC LIMIT 1
是一个臭名昭著的性能反模式。你可能想试试这个。
SELECT a.img, a.ts
FROM pximg a
JOIN (
SELECT ppoc, MAX(file) file
FROM piximg
GROUP BY ppoc
) b ON a.ppoc = b.ppoc AND a.file = b.file
WHERE ppoc = <<<whatever>>>
这将避免让 MySQL 服务器对包含大块 Blob 的大量行进行排序,只丢弃除一个之外的所有行。
【讨论】:
非常感谢您的帮助! 1.) SHOW TABLES 显示 [Index_length] => 0 ... 2) 和 3) 到目前为止没有帮助。 5)查询确实如此,结果是“Using where;Using index”,它的速度和预期的一样快——非常感谢!但我仍在调查为什么原始查询(带有绑定)没有使用主键...以上是关于文件排序而不是索引扫描的主要内容,如果未能解决你的问题,请参考以下文章