【问题标题】:MySQL poor performanceMySQL性能不佳
【发布时间】:2014-06-04 23:17:05
【问题描述】:

我的应用程序的一部分存在一个大问题。我正在使用 SQLAlchemy 和 MySQL 的组合,大多数事情都运行良好,但是有一种痒会永远加载,有时甚至 5-6 分钟,加载客户列表。该表大约有 3000 行,这对于数据库标准来说应该是相当小的,我在一个稍大的表(25k 行)上进行了简单的连接。

SQL Alchemy 中的查询如下:

last_inv = db.session.query(Sales.id).order_by(Sales.invoice_date.desc()).filter(Customer.email == Sales.email).limit(1).correlate(Customer)
results = db.session.query(Customer, last_inv.as_scalar()).filter_by(archive=0)

原始 SQL 如下所示:

SELECT customer.id AS customer_id
     , customer.first_name AS customer_first_name
     , customer.middle_name AS customer_middle_name
     , customer.last_name AS customer_last_name
     , customer.email AS customer_email
     , customer.password AS customer_password
     , customer.address1 AS customer_address1
     , customer.address2 AS customer_address2
     , customer.city AS customer_city
     , customer.state AS customer_state
     , customer.zip AS customer_zip
     , customer.country AS customer_country
     , customer.phone AS customer_phone
     , customer.cell_phone AS customer_cell_phone
     , customer.current_plan AS customer_current_plan
     , customer.minutes_current_plan AS customer_minutes_current_plan
     , customer.orig_sales_id AS customer_orig_sales_id
     , customer.sales_id AS customer_sales_id
     , customer.team_id AS customer_team_id
     , customer.refill_date AS customer_refill_date
     , customer.minutes_refill_date AS customer_minutes_refill_date
     , customer.active AS customer_active
     , customer.archive AS customer_archive
     , customer.imported AS customer_imported
     , customer.ipaddress AS customer_ipaddress
     , customer.auto_renewal AS customer_auto_renewal
     , customer.signup_date AS customer_signup_date
     , customer.esn AS customer_esn
     , customer.last_update_date AS customer_last_update_date
     , customer.last_update_by AS customer_last_update_by
     , customer.notes AS customer_notes
     , customer.current_pin AS customer_current_pin
     , customer.minutes_current_pin AS customer_minutes_current_pin
     , customer.security_pin AS customer_security_pin
     , (SELECT sales.id  
          FROM sales 
         WHERE customer.email = sales.email 
         ORDER 
            BY sales.invoice_date DESC LIMIT 1) AS anon_1 
  FROM customer 
 WHERE customer.team_id = 1 
   AND customer.archive = 0

我尝试了很多东西,但这真的开始让我感到绝望。这一切都在亚马逊上运行,htop 在运行时显示 mysql 的使用率为 100%。 phpmyadmin 上的查询探查器,HeidiSQL 显示在不到两秒的时间内完成(当没有在 cahce 中被命中时),所以它不是导致此问题的实际查询(据我理解)。

这是EXPLAIN 显示的内容:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   PRIMARY customer    ALL NULL    NULL    NULL    NULL    3621    Using where
2   DEPENDENT SUBQUERY  sales   ALL NULL    NULL    NULL    NULL    22619   Using where;    Using filesort

来自 phpmyadmin 的 Profiler 是 here 和视觉表示 here

我在 EC2 上运行一个 m1.small 实例,内存为 1650MB。

我也运行了一个 mysqlprofiler,这是我所做的优化结果beforeafter。我的my.cnf 文件是here

我尝试在表上运行OPTIMIZE,但由于某种原因,未优化表的数量始终为 98,所以我想我做错了什么。我为此使用了this 脚本,以及phpmyadmin 中的原始sql,但没有成功。

【问题讨论】:

  • 相关子查询通常表现不佳
  • 您在customer.emailsales.email 上有索引吗?
  • 我现在做!第二个,sales.email 没有索引,完全忘记了这一点。哇,这现在明显更快了,非常感谢! :)

标签: mysql performance amazon-ec2 sqlalchemy query-optimization


【解决方案1】:

尝试创建这个多列索引,这样可以加快查询速度:

CREATE INDEX sales_eml_invdat ON sales( email, invoice_date );

甚至三列

CREATE INDEX sales_eml_invdat_id ON sales( email, invoice_date, id );

但仅限于id 不是主键列的情况。
如果id是主键,那么前一个索引就足够了。

---- 编辑 ------

对不起,我忘了 MySql 没有其他 DBMS 聪明。
它本身无法检测到这种情况,必须明确告诉他如何去做。
请将子查询改写为:

SELECT sales.id  
FROM sales 
WHERE customer.email = sales.email 
ORDER BY sales.email DESC, sales.invoice_date DESC 
LIMIT 1

此更改使MySql 可以使用( email, invoice_date ) 索引来跳过文件排序,请尝试一下。

【讨论】:

  • 两个索引,一个主键和一个常规索引与多列索引有区别吗?我已经在电子邮件列中添加了索引...
  • 是的,这是有区别的,但这是一个巨大的话题。请阅读此链接:dev.mysql.com/doc/refman/5.7/en/range-optimization.html 和此链接:dev.mysql.com/doc/refman/5.7/en/order-by-optimization.html 以了解 mysql 如何使用单列和多列索引。使用单索引 MySql 必须始终读取sales 表并执行文件排序,使用多列索引它可以直接从索引中读取所有需要的数据并跳过排序操作。
  • 谢谢!我现在确定,因为我在那里使用排序,所以在这种情况下,多列应该更好,而是创建那个。
  • 请试一试,对比创建索引前和创建索引后的explain plan,应该是有区别的-->第二个方案中缺少using filesort
  • 嗯,我现在收到 this... 仍然是文件排序...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-09
  • 2014-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-20
相关资源
最近更新 更多