本地 MySQL 查询和生产服务器查询执行时间之间的差异
Difference between local MySQL query and production server query execution times
我正在构建一个使用大量数据库查询的网站,所以我有点担心会发生这种情况。
所以,这里的问题是,我有几个使用大量 JOIN
的查询,其中一些 table 有几千个条目,而其他一些则有大约 200-30 万个条目。我有过网站变慢的经历,我不得不优化一些查询。
问题是,在这种情况下,在我的本地计算机上,使用这些查询的特定部分需要大约 2.5 秒才能加载,并且启用网络节流作为常规 wi-fi。使用 Good Wi-Fi 加载大约需要 1.3 秒。
在我的生产服务器上,它是 DigitalOcean 上的一个虚拟机,它需要大约 5 分钟! 使用完全相同的查询加载完全相同的内容。现在我不是专家,但我的电脑比 DigitalOcean 上的生产服务器快 120 倍。
我的笔记本电脑具有以下规格:Intel Core i7-6700 HQ,16 GB DDR4 RAM,服务器 运行 在 5400 RPM HDD 上,它甚至不在我的 SSD 驱动器上,那只是MySQL 引擎是。
生产服务器最初是一个具有 1GB RAM 和 1 个 VCPU 的基本 DO 实例。我认为它可能需要一些提升,所以我临时将它升级为具有 2 个 VCPU 和 2 GB 的 RAM,但这没有任何区别。其他部分加载速度非常快,除了使用大量连接的部分。
现在,我不是专家,但我的计算机并不比服务器快 120 倍,而且它还运行许多其他进程。我确实有一个 GeForce 1070M,但我认为这不会影响 mysql 性能。
我尝试将查询分隔成尽可能少的 JOIN
秒,然后执行多个简单查询以将附加信息添加到我的信息数组中,但后来我遇到了一个不同的问题。即使在我的电脑上也有这种逻辑,它卡住了大约 4-5 秒,然后突然加载了内容。
下面是 Chrome 的网络选项卡的屏幕截图,显示了时间差异。正如您所看到的,除了初始加载之外,其他所有内容都加载得非常快。我很确定这是一个 MySQL 问题,但差异是惊人的。我正在考虑尝试在 DigitalOcean 上使用 6VCPU 的 16GB 内存实例加载网站,看看它是否与 memory/cpu 相关,但我不确定我的客户是否愿意每月支付 80 美元或更多虚拟机。
我想到的一个可能的解决方案是将 Localidades
和 Asentamientos
table(它们都有大约 200-300k 个条目)分成 32 个较小的 tables,一个代表墨西哥的每个州,每个州都有一个特殊的功能来引用另一个州 table,但我认为这既不是可扩展的也不是好的做法。
我还在下面添加了查询的计算成本。
我的本地计算机有:
- Windows 10 1803
- Apache/2.4.25 (Win64)
- MySQL 5.7.23
我的生产服务器有:
- Ubuntu 18.04.1 LTS
- Apache/2.4.29 (Ubuntu)
- 5.7.24-0ubuntu0.18.04.1
知道我能做些什么来解决这个问题吗?
生成的查询如下:
SELECT
`Propiedades`.*,
`Propiedades`.`directorio` AS `main_dir`,
DATEDIFF(Propiedades.fecha_finalizacion,
'2018-12-02 11:11:49') AS quedan,
`OperacionesPorPropiedad`.*,
`Operaciones`.`nombre_operacion`,
`Operaciones`.`nombre_operacion_slug`,
`TiposDePropiedades`.*,
`FotografiasPorPropiedad`.*,
`Empresas`.`nombre_empresa`,
`Estados`.*,
`Municipios`.*,
`Localidades`.*,
`Asentamientos`.*,
`Clientes`.`nombres`,
`Clientes`.`apellidos`,
`Clientes`.`email`,
`TiposDeClientes`.*
FROM
`Propiedades`
JOIN
`OperacionesPorPropiedad` ON `OperacionesPorPropiedad`.`id_propiedad` = `Propiedades`.`id_propiedad`
JOIN
`Operaciones` ON (`Operaciones`.`id_operacion` = `OperacionesPorPropiedad`.`id_operacion`
AND `OperacionesPorPropiedad`.`id_propiedad` = Propiedades.id_propiedad)
JOIN
`TiposDePropiedades` ON `TiposDePropiedades`.`id_tipo` = `Propiedades`.`id_tipo`
JOIN
`FotografiasPorPropiedad` ON (`FotografiasPorPropiedad`.`id_propiedad` = `Propiedades`.`id_propiedad`
AND `FotografiasPorPropiedad`.`orden` = 1)
JOIN
`Empresas` ON `Empresas`.`id_empresa` = `Propiedades`.`id_empresa`
JOIN
`Estados` ON `Estados`.`id_estado` = `Propiedades`.`id_estado`
LEFT OUTER JOIN
`Municipios` ON `Municipios`.`id_municipio` = `Propiedades`.`id_municipio`
LEFT OUTER JOIN
`Localidades` ON `Localidades`.`id_localidad` = `Propiedades`.`id_localidad`
LEFT OUTER JOIN
`Asentamientos` ON `Asentamientos`.`id_asentamiento` = `Propiedades`.`id_asentamiento`
JOIN
`Clientes` ON `Clientes`.`id_cliente` = `Empresas`.`id_cliente`
JOIN
`TiposDeClientes` ON (`Clientes`.`id_tipo_cliente` = `TiposDeClientes`.`id_tipo_cliente`
AND `Clientes`.`id_cliente` = `Empresas`.`id_cliente`)
WHERE
`Propiedades`.`id_estatus_propiedad` = 1
GROUP BY `Propiedades`.`id_propiedad`
ORDER BY FIELD(`Propiedades`.`destacada`, '1', '0') , FIELD(`Clientes`.`id_tipo_cliente`, 1, 2, 3) , RAND()
LIMIT 24
抱歉,大家耽误了时间...这是一个新手错误,我在导入数据库时没有阅读错误消息。
当我生成 mysqldump 时,一些 table 名称被错误地生成为仅包含小写字母,导致导入时出错。
由于所有的索引都在错误指令之后,它们从未被执行,所以我基本上进行了非索引完整 table 扫描,这就是为什么加载结果需要很长时间。
我更正了我的 SQL 文件并再次创建了数据库,它非常有效。抱歉浪费你们的时间。
PS:我实际上将服务器提升到 16GB 内存和 6 个 VCPU,但没有任何区别。
这会给你一个合理的 24 行吗?还是您依赖其他 table 的过滤?
WHERE P.`id_estatus_propiedad` = 1
ORDER BY FIELD(P.`destacada`, '1', '0') ,
FIELD(C.`id_tipo_cliente`, 1, 2, 3) ,
RAND()
LIMIT 24
如果是,请考虑以下事项:
您当前的查询正在从 table 的 手 中拖出整行,然后打乱它们,最后只提供 24。
更好的方法是先算出是哪个24,然后去了解详情:
SELECT lots-of-stuff
FROM ( SELECT id_propiedad
FROM Propiedades AS P1
JOIN ... -- as few as needed to get to Clientes
JOIN `Clientes` AS C1 ON C1.`id_cliente` = Em.`id_cliente`
WHERE P1.`id_estatus_propiedad` = 1
ORDER BY FIELD(P1.`destacada`, '1', '0') ,
FIELD(C1.`id_tipo_cliente`, 1, 2, 3) ,
RAND()
LIMIT 24
) AS x
JOIN `Propiedades` AS P ON P.id_propiedad = x.id_propiedad
JOIN `OperacionesPorPropiedad` AS OP ON OP.`id_propiedad` = P.`id_propiedad`
JOIN `Operaciones` AS O ON (O.`id_operacion` = OP.`id_operacion` ...
...
-- no WHERE, GROUP BY, or LIMIT, but repeat the ORDER BY:
ORDER BY FIELD(P.`destacada`, '1', '0') ,
FIELD(C.`id_tipo_cliente`, 1, 2, 3) , RAND()
回到性能差异的问题...
- 您的个人机器
innodb_buffer_pool_size
比云中的小型 VM 更有价值?
- 您正在从大约一打 table 的许多行中获取所有列。
- 您(当前)首先收集大量 潜在 输出行,然后使用
GROUP BY
消除重复项,最后 LIMITing
到仅 24。 temp table 的大小可能很大。 ("inflate-deflate" JOIN
加上 GROUP BY
的综合征。
- 您可能在某些
*
列列表中有 TEXT
列;这加剧了温度 table 问题。
这些结合起来会导致 fast/slow 性能。我的建议,如果可行,可以消除大部分。
另外 FotografiasPorPropiedad
需要 INDEX(id_propiedad, orden)
(任意顺序)。
我正在构建一个使用大量数据库查询的网站,所以我有点担心会发生这种情况。
所以,这里的问题是,我有几个使用大量 JOIN
的查询,其中一些 table 有几千个条目,而其他一些则有大约 200-30 万个条目。我有过网站变慢的经历,我不得不优化一些查询。
问题是,在这种情况下,在我的本地计算机上,使用这些查询的特定部分需要大约 2.5 秒才能加载,并且启用网络节流作为常规 wi-fi。使用 Good Wi-Fi 加载大约需要 1.3 秒。
在我的生产服务器上,它是 DigitalOcean 上的一个虚拟机,它需要大约 5 分钟! 使用完全相同的查询加载完全相同的内容。现在我不是专家,但我的电脑比 DigitalOcean 上的生产服务器快 120 倍。
我的笔记本电脑具有以下规格:Intel Core i7-6700 HQ,16 GB DDR4 RAM,服务器 运行 在 5400 RPM HDD 上,它甚至不在我的 SSD 驱动器上,那只是MySQL 引擎是。
生产服务器最初是一个具有 1GB RAM 和 1 个 VCPU 的基本 DO 实例。我认为它可能需要一些提升,所以我临时将它升级为具有 2 个 VCPU 和 2 GB 的 RAM,但这没有任何区别。其他部分加载速度非常快,除了使用大量连接的部分。
现在,我不是专家,但我的计算机并不比服务器快 120 倍,而且它还运行许多其他进程。我确实有一个 GeForce 1070M,但我认为这不会影响 mysql 性能。
我尝试将查询分隔成尽可能少的 JOIN
秒,然后执行多个简单查询以将附加信息添加到我的信息数组中,但后来我遇到了一个不同的问题。即使在我的电脑上也有这种逻辑,它卡住了大约 4-5 秒,然后突然加载了内容。
下面是 Chrome 的网络选项卡的屏幕截图,显示了时间差异。正如您所看到的,除了初始加载之外,其他所有内容都加载得非常快。我很确定这是一个 MySQL 问题,但差异是惊人的。我正在考虑尝试在 DigitalOcean 上使用 6VCPU 的 16GB 内存实例加载网站,看看它是否与 memory/cpu 相关,但我不确定我的客户是否愿意每月支付 80 美元或更多虚拟机。
我想到的一个可能的解决方案是将 Localidades
和 Asentamientos
table(它们都有大约 200-300k 个条目)分成 32 个较小的 tables,一个代表墨西哥的每个州,每个州都有一个特殊的功能来引用另一个州 table,但我认为这既不是可扩展的也不是好的做法。
我还在下面添加了查询的计算成本。
我的本地计算机有:
- Windows 10 1803
- Apache/2.4.25 (Win64)
- MySQL 5.7.23
我的生产服务器有:
- Ubuntu 18.04.1 LTS
- Apache/2.4.29 (Ubuntu)
- 5.7.24-0ubuntu0.18.04.1
知道我能做些什么来解决这个问题吗?
生成的查询如下:
SELECT
`Propiedades`.*,
`Propiedades`.`directorio` AS `main_dir`,
DATEDIFF(Propiedades.fecha_finalizacion,
'2018-12-02 11:11:49') AS quedan,
`OperacionesPorPropiedad`.*,
`Operaciones`.`nombre_operacion`,
`Operaciones`.`nombre_operacion_slug`,
`TiposDePropiedades`.*,
`FotografiasPorPropiedad`.*,
`Empresas`.`nombre_empresa`,
`Estados`.*,
`Municipios`.*,
`Localidades`.*,
`Asentamientos`.*,
`Clientes`.`nombres`,
`Clientes`.`apellidos`,
`Clientes`.`email`,
`TiposDeClientes`.*
FROM
`Propiedades`
JOIN
`OperacionesPorPropiedad` ON `OperacionesPorPropiedad`.`id_propiedad` = `Propiedades`.`id_propiedad`
JOIN
`Operaciones` ON (`Operaciones`.`id_operacion` = `OperacionesPorPropiedad`.`id_operacion`
AND `OperacionesPorPropiedad`.`id_propiedad` = Propiedades.id_propiedad)
JOIN
`TiposDePropiedades` ON `TiposDePropiedades`.`id_tipo` = `Propiedades`.`id_tipo`
JOIN
`FotografiasPorPropiedad` ON (`FotografiasPorPropiedad`.`id_propiedad` = `Propiedades`.`id_propiedad`
AND `FotografiasPorPropiedad`.`orden` = 1)
JOIN
`Empresas` ON `Empresas`.`id_empresa` = `Propiedades`.`id_empresa`
JOIN
`Estados` ON `Estados`.`id_estado` = `Propiedades`.`id_estado`
LEFT OUTER JOIN
`Municipios` ON `Municipios`.`id_municipio` = `Propiedades`.`id_municipio`
LEFT OUTER JOIN
`Localidades` ON `Localidades`.`id_localidad` = `Propiedades`.`id_localidad`
LEFT OUTER JOIN
`Asentamientos` ON `Asentamientos`.`id_asentamiento` = `Propiedades`.`id_asentamiento`
JOIN
`Clientes` ON `Clientes`.`id_cliente` = `Empresas`.`id_cliente`
JOIN
`TiposDeClientes` ON (`Clientes`.`id_tipo_cliente` = `TiposDeClientes`.`id_tipo_cliente`
AND `Clientes`.`id_cliente` = `Empresas`.`id_cliente`)
WHERE
`Propiedades`.`id_estatus_propiedad` = 1
GROUP BY `Propiedades`.`id_propiedad`
ORDER BY FIELD(`Propiedades`.`destacada`, '1', '0') , FIELD(`Clientes`.`id_tipo_cliente`, 1, 2, 3) , RAND()
LIMIT 24
抱歉,大家耽误了时间...这是一个新手错误,我在导入数据库时没有阅读错误消息。
当我生成 mysqldump 时,一些 table 名称被错误地生成为仅包含小写字母,导致导入时出错。
由于所有的索引都在错误指令之后,它们从未被执行,所以我基本上进行了非索引完整 table 扫描,这就是为什么加载结果需要很长时间。
我更正了我的 SQL 文件并再次创建了数据库,它非常有效。抱歉浪费你们的时间。
PS:我实际上将服务器提升到 16GB 内存和 6 个 VCPU,但没有任何区别。
这会给你一个合理的 24 行吗?还是您依赖其他 table 的过滤?
WHERE P.`id_estatus_propiedad` = 1
ORDER BY FIELD(P.`destacada`, '1', '0') ,
FIELD(C.`id_tipo_cliente`, 1, 2, 3) ,
RAND()
LIMIT 24
如果是,请考虑以下事项:
您当前的查询正在从 table 的 手 中拖出整行,然后打乱它们,最后只提供 24。
更好的方法是先算出是哪个24,然后去了解详情:
SELECT lots-of-stuff
FROM ( SELECT id_propiedad
FROM Propiedades AS P1
JOIN ... -- as few as needed to get to Clientes
JOIN `Clientes` AS C1 ON C1.`id_cliente` = Em.`id_cliente`
WHERE P1.`id_estatus_propiedad` = 1
ORDER BY FIELD(P1.`destacada`, '1', '0') ,
FIELD(C1.`id_tipo_cliente`, 1, 2, 3) ,
RAND()
LIMIT 24
) AS x
JOIN `Propiedades` AS P ON P.id_propiedad = x.id_propiedad
JOIN `OperacionesPorPropiedad` AS OP ON OP.`id_propiedad` = P.`id_propiedad`
JOIN `Operaciones` AS O ON (O.`id_operacion` = OP.`id_operacion` ...
...
-- no WHERE, GROUP BY, or LIMIT, but repeat the ORDER BY:
ORDER BY FIELD(P.`destacada`, '1', '0') ,
FIELD(C.`id_tipo_cliente`, 1, 2, 3) , RAND()
回到性能差异的问题...
- 您的个人机器
innodb_buffer_pool_size
比云中的小型 VM 更有价值? - 您正在从大约一打 table 的许多行中获取所有列。
- 您(当前)首先收集大量 潜在 输出行,然后使用
GROUP BY
消除重复项,最后LIMITing
到仅 24。 temp table 的大小可能很大。 ("inflate-deflate"JOIN
加上GROUP BY
的综合征。 - 您可能在某些
*
列列表中有TEXT
列;这加剧了温度 table 问题。
这些结合起来会导致 fast/slow 性能。我的建议,如果可行,可以消除大部分。
另外 FotografiasPorPropiedad
需要 INDEX(id_propiedad, orden)
(任意顺序)。