如何提高MYSQL查询的性能?

Posted

技术标签:

【中文标题】如何提高MYSQL查询的性能?【英文标题】:How to improve the performance of MYSQL query? 【发布时间】:2013-03-21 00:32:58 【问题描述】:

我目前正在将数据馈送上传到我的数据库中。由于存在超过 1 千万条记录,我的数据库中被转储了。我需要改进或提高我网站中的 mysql 查询性能。下面是我执行的查询....

select SUM(SPRICE) AS Tot, MIN(SMIN) AS Min from 
(SELECT COUNT(LS.SALEPRICE) AS SPRICE, MIN(LS.SALEPRICE) AS SMIN 
 FROM `linkshare` LS 
 WHERE LS.`PRODUCTNAME` LIKE '%DVS Men\'s Comanche Skate Shoe%' 
 UNION 
 SELECT COUNT(CJ.PRICE) AS SPRICE, MIN(CJ.PRICE) AS SMIN 
 FROM `cjfeeds` CJ 
 WHERE CJ.NAME LIKE '%DVS Men\'s Comanche Skate Shoe%' ) AS xyz

在上述查询中,它在本地数据库中完美运行,我的数据库包含不到 5 万条记录...如何改进我在实时服务器中的查询?请指导我.....

我的查询也花了 39.4626 秒。如何减少此查询的运行时间?

【问题讨论】:

你需要标准化你的数据库。 Pick something other than Fisher Price My First SQL Server?如果您想要一个严肃的评论:您的 LIKE 带有通配符匹配以及字符串的开头和结尾可能会对您的查询造成最大的伤害。 请注意,您应该在查询中使用UNION ALL 而不是UNION(默认为UNION DISTINCT)。 【参考方案1】:

好的,我要编辑我的答案以首先更具体地处理您的查询,之前的建议会起作用,但您的查询相当疯狂,所以让我们讨论一下原因。

您需要的一切实际上都在此处的 EXPLAIN 输出中,您的 UNION 导致了 340 万次元组访问,而派生表查询(连接后)约为 90 万。

Add an index 在两个表中的 PRODUCTNAME 上

联合?什么?我假设这里发生的事情是您有两个非常相似/相同的表,并且您正在对这个相当狡猾的过滤器查询进行 UNION 以基本上将一个连接到另一个。 这是第一个警告标志,如果您可以简化此查询并拥有一个类型为枚举的表,则此查询会更快,例如type (LS|CJ) 或外键和类型表,具体取决于您的要求。

假设您出于某种原因不想永久执行此操作,(并且您应该这样做),您可以 create a temporary table 从两个选择中进行此计算。一旦您将所有信息都放在一个表中,因为您正在做一个简单的选择您的计数,总和会很快。

MySQL 有一个 EXPLAIN 命令,您可以为任何查询添加前缀,例如

EXPLAIN select SUM(SPRICE) AS Tot, MIN(SMIN) AS Min from (SELECT COUNT(LS.SALEPRICE) AS SPRICE, MIN(LS.SALEPRICE) AS SMIN FROM `linkshare` LS WHERE LS.`PRODUCTNAME` LIKE '%DVS Men\'s Comanche Skate Shoe%' UNION SELECT COUNT(CJ.PRICE) AS SPRICE, MIN(CJ.PRICE) AS SMIN FROM `cjfeeds` CJ WHERE CJ.NAME LIKE '%DVS Men\'s Comanche Skate Shoe%' ) AS xyz;

输出对于初学者来说可能有些神秘,请查看tutorial 以获取更多信息。一般来说:

尽可能避免使用“LIKE %blah%”样式的查询,因为 Mark Ba​​nnister 建议这些查询不会使用您创建的任何索引。 为选择中使用的任何字段创建索引(在超过一千行的表中)。 让快速增长的表格尽可能精简 尽可能使用固定宽度的列,例如char/varchar 而不是 TEXT/BLOB

如果您在大型数据集上运行复合慢查询,请考虑缓存它/tuning您的 my.cnf 表缓存大小。

总之,总是尽量做精确的字符串匹配,因为这些可以被索引。您的问题源于规范化不良的表结构。规范化只是意味着(以高级非技术方式)您以一种减少重复的方式组织数据,因此更加一致。好处是它可以更轻松地对其进行有效查询。 如果您认为需要通配符查询,您可能需要对产品进行分类 例如进入像'shoes'这样的类别,为此,添加一个product_categories 表,其模式类似于|category_id, category_name|。然后在您的产品表中(如果产品只能属于一个类别)添加一个外键,例如category_id,给category_id字段添加索引,然后通过category_id查询产品

例如select * FROM products where category_id=5

如果您认为需要对数据进行模糊匹配,那听起来确实有点杂乱无章。如果不可避免,请查看您的 devops 人员是否可以设置读取从站,以便您的慢查询不会损害任何重要系统。

【讨论】:

如果你以错误的方式组装引擎,调整它是没有用的。 请注意,like 'blah%' 可能能够使用索引,但 like '%blah%' 不太可能使用索引。 我在价格字段中创建了索引。但是我如何在我的查询中使用这个索引。 嗨@Mark,我更新了解释查询屏幕截图。请给我一些建议。 正如@MarkBannister 提到的,始终避免使用 '%blah%' 查询,因为它不会使用索引,因为索引将匹配字符串左侧的某个前缀(如果您在产品名称)。如果还没有,则添加一个并使用具有精确比较的查询,该比较适合索引,例如product_name = '某个名字'。【参考方案2】:

使用EXPLAIN 找出引擎盖下发生的事情

【讨论】:

以上是关于如何提高MYSQL查询的性能?的主要内容,如果未能解决你的问题,请参考以下文章

如何简化/提高这个 MySQL 查询的性能?

如何提高mysql查询速度

如何强制连接顺序以提高 MYSQL 中的查询性能?

如何提高查询性能?

如何提高 Django 管理员搜索相关字段(MySQL)中的查询性能

提高mysql查询的性能