从表中有百万记录,当我从中提取数据时,
我想检查所请求的数据是否存在,那么哪条路径效率哪个更快然后另一条?
$Query = '
SELECT n.id
FROM names n
INNER JOIN ages a ON n.id = a.aid
INNER JOIN regions r ON n.id = r.rid
WHERE id = :id
';
$stmt->prepare($Query);
$stmt->execute(['id' => $id]);
if ($stmt->rowCount() == 1) {
$row = $stmt->fetch();
......................
} else {
exit();
}
或
$EXISTS = 'SELECT EXISTS (
SELECT n.fname, n.lname, a.age, r.region
FROM names n
INNER JOIN ages a ON n.id = a.aid
INNER JOIN regions r ON n.id = r.rid
WHERE id = :id
LIMIT 1
)
';
$stmt->prepare($EXISTS);
$stmt->execute(['id' => $id]);
if ($stmt->fetchColumn() == 1) {
$stmt->prepare($Query);
$stmt->execute(['id' => $id]);
$row = $stmt->fetch();
......................
} else {
exit();
}
请注意,id
为PRIMARY (INT)
且aid, rid
为INDEXED (INT)
答案 0 :(得分:1)
您展示的两种方法几乎肯定是等效的,几乎没有可测量的性能差异。
SELECT n.id
FROM names n
INNER JOIN ages a ON n.id = a.aid
INNER JOIN regions r ON n.id = r.rid
WHERE id = :id
我认为names.id
是该表的主键。主键查找非常快。
然后它将对其他两个表进行二次密钥查找,它将是一个仅索引访问,因为它没有引用这些表的其他列。
您应该学习如何使用EXPLAIN来分析MySQL的优化计划。这是您在想要提高SQL查询性能时应该练习的技能。
请参阅https://dev.mysql.com/doc/refman/5.7/en/using-explain.html
mysql> explain SELECT n.id
-> FROM names n
-> INNER JOIN ages a ON n.id = a.aid
-> INNER JOIN regions r ON n.id = r.rid
-> WHERE id = 1;
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
| 1 | SIMPLE | n | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | Using index |
| 1 | SIMPLE | a | NULL | ref | aid | aid | 5 | const | 1 | 100.00 | Using index |
| 1 | SIMPLE | r | NULL | ref | rid | rid | 5 | const | 1 | 100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
我们看到每个表访问都使用索引(虽然您没有在问题中提供SHOW CREATE TABLE
,但我假设索引)。
与使用SELECT EXISTS(...)
mysql> explain SELECT EXISTS (
-> SELECT n.id
-> FROM names n
-> INNER JOIN ages a ON n.id = a.aid
-> INNER JOIN regions r ON n.id = r.rid
-> WHERE id = 1
-> LIMIT 1);
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+----------------+
| 1 | PRIMARY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
| 2 | SUBQUERY | n | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | Using index |
| 2 | SUBQUERY | a | NULL | ref | aid | aid | 5 | const | 1 | 100.00 | Using index |
| 2 | SUBQUERY | r | NULL | ref | rid | rid | 5 | const | 1 | 100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+----------------+
子查询看起来与第一个查询优化计划相同;它仍然以相同的方式使用索引。但它被降级为子查询。可能没什么大不同,但还有一件事。
唯一的好处是SELECT EXISTS...
查询保证只返回一行具有true / false值。第一个查询可能返回包含零行,一行或多行的结果集,具体取决于查询中JOIN的匹配程度。差异不是性能差异(除非它返回那么多行,将结果集转移到客户端需要时间,或者使用大量内存来保存客户端中的结果集),但只是为了方便你编码的方式。
答案 1 :(得分:0)
不规范年龄;这只是浪费空间和时间。 age
(假设它是'年')可以适合1字节TINYINT UNSIGNED
(范围:0..255)并避免JOIN
查找。请注意,aid
似乎是一个4字节的INT
,可以容纳数十亿个不同的值 - 你有数十亿不同的年龄吗?
也许改变regions
也是值得的。
在第一个查询中,两个JOINs
只会验证年龄和地区中是否有行。那可能浪费。
EXISTS
停止。所以LIMIT 1
非常不必要。