MySQL 查询优化 prestashop
MySQL query optimization prestashop
我目前正在编写一个 SQL 语句,用于在 Prestashop 安装数据库中获取特定国家/地区的时区。我使用的 tables 是:
- ps_timezone:时区(Canada/Atlantic、America/Adak等)
- ps_country_lang:国家名称(加拿大、美国、法国等)
- ps_country: country table (我知道这个国家就用它,但我想知道它的地区).
- ps_zone:区域(美洲、欧洲、亚洲等)
然后我写了下面的查询(id_country =4 是加拿大):
SELECT tz.id_timezone, tz.name FROM ps_timezone tz WHERE tz.name LIKE CONCAT((SELECT cl.name FROM ps_country_lang cl WHERE cl.id_country=4 and cl.id_lang = 1) ,'%') OR tz.name LIKE CONCAT((SELECT CASE WHEN INSTR(z.name, 'Europe') > 0 THEN 'Europe' WHEN INSTR(z.name, 'America') > 0 THEN 'America' ELSE z.name END as zone_name FROM ps_zone z JOIN ps_country c ON z.id_zone = c.id_zone WHERE c.id_country =4), '%') ORDER BY CASE WHEN tz.name LIKE CONCAT((SELECT cl.name FROM ps_country_lang cl WHERE cl.id_country=4 and cl.id_lang = 1) ,'%') THEN 1 ELSE 2 END, tz.name ASC;
查询正常,但希望前辈们对我的个人提升和文化优化提出建议。
首先,我使用 LIKE 来验证时区是否以国家/地区名称开头:
tz.name LIKE CONCAT((SELECT cl.name FROM ps_country_lang cl WHERE cl.id_country=4 and cl.id_lang = 1) ,'%')
或区域名称:
tz.name LIKE CONCAT((SELECT CASE WHEN INSTR(z.name, 'Europe') > 0 THEN 'Europe' WHEN INSTR(z.name, 'America') > 0 THEN 'America' ELSE z.name END as zone_name FROM ps_zone z JOIN ps_country c ON z.id_zone = c.id_zone WHERE c.id_country =4), '%')
我怀疑 LIKE 关键字不是最高效的...提取时区的第一部分并像这样直接进行比较会不会更高效:
WHERE LEFT(tz.name, INSTR(tz.name, "/") - 1) = (SELECT cl.name FROM ps_country_lang cl WHERE cl.id_country=4 and cl.id_lang = 1)
其次,我在 ORDER BY 中使用 SELECT,因此首先显示带有国家/地区名称的时区。
ORDER BY CASE WHEN tz.name LIKE CONCAT((SELECT cl.name FROM ps_country_lang cl WHERE cl.id_country=4 and cl.id_lang = 1) ,'%') THEN 1 ELSE 2 END, tz.name ASC
当然,这是一个美学问题,但我担心性能问题。由于查询使用的是固定值(我在将查询发送到数据库之前知道国家/地区 ID,英语的语言应始终为 1),因此查询只会 运行 一次,还是每行都会 运行 ?
此外,我不太喜欢它,因为我在 WHERE 子句和 ORDER BY 子句中都有完全相同的子查询。我不能使用 SELECT 子句中的别名,因为首先执行 WHERE 子句(无论如何它会迫使我无用地 return 一行)。
当然,如果我有国家/地区的时区,最好的做法是排除大陆名称的时区...
我知道这些都不是简单的问题,但认为这些对于许多像我一样认真学习正确编程的初学者来说是有趣的事情。
谢谢,
来自蒙特利尔的 Jonathan Parent-Lévesque
我将通过利用 PHP 5.2 中引入的 DateTimeZone PHP 组件来简化此查询,其中 returns 给定 ISO 3166-1 国家/地区的时区标识符代码(例如 "CA" 代表加拿大)。
示例:
<?php
$country_iso_code = 'CA';
$timezone = DateTimeZone::listIdentifiers(DateTimeZone::PER_COUNTRY, $country_iso_code);
echo $timezone[0]; /* Multiple timezones per country, get the 1st one */
我目前正在编写一个 SQL 语句,用于在 Prestashop 安装数据库中获取特定国家/地区的时区。我使用的 tables 是:
- ps_timezone:时区(Canada/Atlantic、America/Adak等)
- ps_country_lang:国家名称(加拿大、美国、法国等)
- ps_country: country table (我知道这个国家就用它,但我想知道它的地区).
- ps_zone:区域(美洲、欧洲、亚洲等)
然后我写了下面的查询(id_country =4 是加拿大):
SELECT tz.id_timezone, tz.name FROM ps_timezone tz WHERE tz.name LIKE CONCAT((SELECT cl.name FROM ps_country_lang cl WHERE cl.id_country=4 and cl.id_lang = 1) ,'%') OR tz.name LIKE CONCAT((SELECT CASE WHEN INSTR(z.name, 'Europe') > 0 THEN 'Europe' WHEN INSTR(z.name, 'America') > 0 THEN 'America' ELSE z.name END as zone_name FROM ps_zone z JOIN ps_country c ON z.id_zone = c.id_zone WHERE c.id_country =4), '%') ORDER BY CASE WHEN tz.name LIKE CONCAT((SELECT cl.name FROM ps_country_lang cl WHERE cl.id_country=4 and cl.id_lang = 1) ,'%') THEN 1 ELSE 2 END, tz.name ASC;
查询正常,但希望前辈们对我的个人提升和文化优化提出建议。
首先,我使用 LIKE 来验证时区是否以国家/地区名称开头:
tz.name LIKE CONCAT((SELECT cl.name FROM ps_country_lang cl WHERE cl.id_country=4 and cl.id_lang = 1) ,'%')
或区域名称:
tz.name LIKE CONCAT((SELECT CASE WHEN INSTR(z.name, 'Europe') > 0 THEN 'Europe' WHEN INSTR(z.name, 'America') > 0 THEN 'America' ELSE z.name END as zone_name FROM ps_zone z JOIN ps_country c ON z.id_zone = c.id_zone WHERE c.id_country =4), '%')
我怀疑 LIKE 关键字不是最高效的...提取时区的第一部分并像这样直接进行比较会不会更高效:
WHERE LEFT(tz.name, INSTR(tz.name, "/") - 1) = (SELECT cl.name FROM ps_country_lang cl WHERE cl.id_country=4 and cl.id_lang = 1)
其次,我在 ORDER BY 中使用 SELECT,因此首先显示带有国家/地区名称的时区。
ORDER BY CASE WHEN tz.name LIKE CONCAT((SELECT cl.name FROM ps_country_lang cl WHERE cl.id_country=4 and cl.id_lang = 1) ,'%') THEN 1 ELSE 2 END, tz.name ASC
当然,这是一个美学问题,但我担心性能问题。由于查询使用的是固定值(我在将查询发送到数据库之前知道国家/地区 ID,英语的语言应始终为 1),因此查询只会 运行 一次,还是每行都会 运行 ?
此外,我不太喜欢它,因为我在 WHERE 子句和 ORDER BY 子句中都有完全相同的子查询。我不能使用 SELECT 子句中的别名,因为首先执行 WHERE 子句(无论如何它会迫使我无用地 return 一行)。
当然,如果我有国家/地区的时区,最好的做法是排除大陆名称的时区...
我知道这些都不是简单的问题,但认为这些对于许多像我一样认真学习正确编程的初学者来说是有趣的事情。
谢谢,
来自蒙特利尔的 Jonathan Parent-Lévesque
我将通过利用 PHP 5.2 中引入的 DateTimeZone PHP 组件来简化此查询,其中 returns 给定 ISO 3166-1 国家/地区的时区标识符代码(例如 "CA" 代表加拿大)。
示例:
<?php
$country_iso_code = 'CA';
$timezone = DateTimeZone::listIdentifiers(DateTimeZone::PER_COUNTRY, $country_iso_code);
echo $timezone[0]; /* Multiple timezones per country, get the 1st one */