我正在建立一个使用大量数据库查询的网站,所以我有点担心这种情况会发生。
所以,这里的问题是,我有几个使用大量JOIN
的查询,一些表有几千个条目,而另一些表有约200-300,000个条目。我曾经历过网站变慢的经历,不得不优化一些查询。
问题是,在这种情况下,在我的本地计算机上,使用那些查询的特定部分需要花费大约2.5秒的时间来加载,并将网络限制启用为常规wi-fi。有了良好的Wi-Fi,加载大约需要1.3秒。
在作为DigitalOcean上的虚拟机的生产服务器上,大约需要5分钟!!使用完全相同的查询加载完全相同的内容。现在我已经不是专家了,但是我的计算机没有比DigitalOcean上的生产服务器快120倍。
我的笔记本电脑具有以下规格:英特尔酷睿i7-6700 HQ,16 GB DDR4 RAM,并且服务器在5400 RPM HDD上运行,它甚至不在我的SSD驱动器上,而这仅是MySQL引擎所在的位置。 / p>
生产服务器最初是具有1GB RAM和1个VCPU的基本DO实例。我以为它可能需要增强,所以我暂时对其进行了升级,使其具有2VCPU和2 GB的RAM,但这没什么区别。除了使用大量连接的那一部分外,其他部分的加载速度非常快。
现在,我还不是专家,但是我的计算机的运行速度并不比服务器快120倍,并且它还可以运行许多其他进程。我确实装有GeForce 1070M,但我认为这不会影响mysql的性能。
我尝试将查询尽可能少地JOIN
中分离,然后执行多个简单查询以将附加信息添加到我的信息数组中,但是然后遇到了另一个问题。即使在我的计算机上也具有这种逻辑,卡住了大约4-5秒钟,然后突然加载了内容。
下面是Chrome的网络标签的屏幕截图,其中显示了时间差异。如您所见,除初始负载外,其他所有负载都非常快。我很确定这是一个MySQL问题,但是区别是惊人的。我正在考虑尝试将站点加载到DigitalOcean上具有6VCPU的16GB内存实例上,以查看其是否与内存/ cpu有关,但是我不确定我的客户愿意为这种VM每月支付80美元或以上
我正在考虑的一种可能的解决方案是将Localidades
和Asentamientos
表(它们都有大约200-300k条目)划分为32个较小的表,每个表针对墨西哥州,并且有一个每个状态都有一个特殊功能来引用另一个表,但是我认为这既不是可扩展的,也不是好的做法。
我还在下面添加了查询的计算成本。
我的本地计算机具有:
我的生产服务器具有:
有什么办法可以解决这个问题吗?
生成的查询如下:
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
答案 0 :(得分:1)
很抱歉让您花费时间...这是一个菜鸟错误,其中导入数据库时我没有阅读错误消息。
当我生成mysqldump时,某些表名使用小写字母错误地生成,并且在导入时导致错误。
由于所有内容的索引都在错误的指令之后,所以它们从未执行过,所以我基本上进行了非索引的全表扫描,这就是为什么要永远加载结果的原因。
我更正了我的SQL文件,并再次创建了数据库,它的工作原理很吸引人。抱歉浪费您的时间。
PS:实际上,我将服务器提升到16GB的RAM和6VCPU,这没有任何区别。
答案 1 :(得分:0)
这会给您合理的24行吗?还是依赖其他表的筛选?
WHERE P.`id_estatus_propiedad` = 1
ORDER BY FIELD(P.`destacada`, '1', '0') ,
FIELD(C.`id_tipo_cliente`, 1, 2, 3) ,
RAND()
LIMIT 24
如果是,请考虑以下因素:
您当前的查询是从表的很多中查找整行,然后对它们进行改组,最后只提供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?GROUP BY
消除重复,最后使用LIMITing
减少到24。临时的大小桌子可能很大。 (JOIN
加GROUP BY
的“充气-放气”综合症。TEXT
列列表中有*
列;这会加剧临时表的问题。这些组合会导致快速/缓慢的性能。我的建议(如果可行)消除了大部分建议。
FotografiasPorPropiedad
也需要INDEX(id_propiedad, orden)
(以任意顺序)。