我目前正在尝试优化运行 4.9452秒的繁重脚本(查询)。然后有一个PHP while循环,根据返回的内容设置一些数组,但这是另一个问题。
编辑 - 用户表约为9000行,user_address表约为3000行,shop_countries约为200行。
这是我的问题:
SELECT
users.id AS user_id,
users.unique_code AS user_unique_code,
users.first_name AS user_first_name,
users.surname AS user_surname,
users.organisation AS user_organisation,
users.telephone AS user_telephone,
users.email AS user_email,
users.password AS user_password,
users.newsletter AS user_newsletter,
user_address.id AS user_address_id,
user_address.user_id AS user_address_user_id,
user_address.nickname AS user_address_nickname,
user_address.address_type AS user_address_type,
user_address.address_line_1 AS user_address_line_1,
user_address.address_line_2 AS user_address_line_2,
user_address.address_line_3 AS user_address_line_3,
user_address.city AS user_address_city,
user_address.postcode AS user_address_postcode,
user_address.country_id AS user_address_country_id,
shop_countries.printable_name
FROM users
LEFT JOIN user_address ON users.id = user_address.user_id
LEFT JOIN shop_countries ON shop_countries.id = user_address.country_id
WHERE (users.surname != "" OR users.first_name != "")
ORDER BY users.surname ASC, users.first_name ASC;
我需要选择所有用户,无论他们是否分配了地址,然后在 IS 可用地址时附加所有国家/地区。
以下是EXPLAIN EXTENDED的结果
到目前为止,似乎如果我要将LEFT JOIN
更改为JOIN
,那么查询将在不到一秒的时间内执行。问题在于我需要所有用户,无论他们是否有地址。
PHP脚本
对于想要查看相应PHP函数以供我参考设计的人,请参阅以下内容:
function getAllUsersWithAddresses() {
$customers = array();
$sql = 'SELECT
users.id AS user_id,
users.unique_code AS user_unique_code,
users.first_name AS user_first_name,
users.surname AS user_surname,
users.organisation AS user_organisation,
users.telephone AS user_telephone,
users.email AS user_email,
users.password AS user_password,
users.newsletter AS user_newsletter,
user_address.id AS user_address_id,
user_address.user_id AS user_address_user_id,
user_address.nickname AS user_address_nickname,
user_address.address_type AS user_address_type,
user_address.address_line_1 AS user_address_line_1,
user_address.address_line_2 AS user_address_line_2,
user_address.address_line_3 AS user_address_line_3,
user_address.city AS user_address_city,
user_address.postcode AS user_address_postcode,
user_address.country_id AS user_address_country_id,
shop_countries.printable_name
FROM users
LEFT JOIN user_address ON users.id = user_address.user_id LEFT JOIN shop_countries ON shop_countries.id = user_address.country_id WHERE (users.surname != "" OR users.first_name != "") ORDER BY users.surname ASC, users.first_name ASC;';
$users_query = mysql_query($sql);
$customers = array();
while($row = getData($users_query)) {
if(!isset($customers[$row['user_id']])) {
$customers[$row['user_id']] = array(
'id' => $row['user_id'],
'unique_code' => $row['user_unique_code'],
'first_name' => $row['user_first_name'],
'surname' => $row['user_surname'],
'organisation' => $row['user_organisation'],
'telephone' => $row['user_telephone'],
'email' => $row['user_email'],
'password' => $row['user_password'],
'newsletter' => $row['user_newsletter']
);
}
if(isset($customers[$row['user_id']]) && !empty($row['user_address_type'])) {
$customers[$row['user_id']]['addresses'][$row['user_address_type']][] = array(
'id' => $row['user_address_id'],
'user_id' => $row['user_address_user_id'],
'nickname' => $row['user_address_nickname'],
'address_type' => $row['user_address_type'],
'address_line_1' => $row['user_address_line_1'],
'address_line_2' => $row['user_address_line_2'],
'address_line_3' => $row['user_address_line_3'],
'city' => $row['user_address_city'],
'postcode' => $row['user_address_postcode']
);
} else {
$customers[$row['user_id']]['addresses'] = array();
}
}
return $customers;
}
答案 0 :(得分:0)
为您的外国ids创建索引
答案 1 :(得分:0)
我无法看到你的解释计划 - 如果你在你的问题中发布它会有所帮助。但是,即使我可以,在不了解数据库结构的情况下也没有多大帮助 - 请包含create table语法和索引。在理想世界中,您还应包括索引基数。
只有两种方法可以让查询更快。减少数据库需要检查的行数,或使DBMS更容易找到要返回的行。
我猜大多数费用来自查询中的2个LEFT JOIN。你肯定有完整的国家名单吗?没有那么多。因此,您应该能够使用内部联接替换第二个外部联接。
WHERE(users.surname!=“”OR users.first_name!=“”)
在mysql查询中使用“OR”可以从根本上改变其行为。你有很多缺少名字的顾客吗?如果它低于5%,那么......
WHERE LENGTH(users.surname) AND LENGTH(users.first_name)
...超过5%且已编入索引......
WHERE users.surname LIKE '_%' AND users.first_name LIKE '_%'
但最大的胜利来自确保您拥有主键和外键的索引。