mysql - Mysql索引表查询慢

标签 mysql database query-performance

我一直致力于提高我的一个数据库(MySQL)查询的性能。问题是我做了这么多之后,我的表现仍然很慢。在我进行更改之前,查询运行时间为 9.54 秒,在更改一些索引后,性能提高到 5.67 秒。

这是我的查询:

Query_time: 5.343565 Lock_time: 0.000302 Rows_sent: 100005 Rows_examined: 200017

代码:

SET timestamp=1455032448;
SELECT 
     id, 
     description,
     unit_price, 
     (SELECT coalesce(sum(quantity),0) from si_invoice_items where product_id = si_products.id) as qty_out ,
     (SELECT coalesce(sum(quantity),0) from si_inventory where product_id = si_products.id) as qty_in ,
     (SELECT coalesce(reorder_level,0)) as reorder_level ,
     (SELECT qty_in - qty_out ) as quantity,
     (SELECT (CASE  WHEN enabled = 0 THEN 'Disabled' ELSE 'Enabled' END )) AS enabled
FROM 
    si_products  
WHERE 
    visible = 1
    AND domain_id = '1'
ORDER BY 
    description asc;

这是所有受影响表的索引信息:

Table Non_unique  Key_name  Seq_in_index  Column_name  Collation  Cardinality  Sub_part  Packed  Null  Index_type   
si_products 0 PRIMARY 1 id A 100005 NULL NULL  BTREE   
si_products 0 PRIMARY 2 domain_id A 100005 NULL NULL  BTREE   
si_products 1 unit_price 1 unit_price A 10000 NULL NULL YESBTREE   
si_products 1 description 1 id A 100005 NULL NULL  BTREE   
si_products 1 description 2 description A 100005 15 NULL  BTREE 

Table  Non_unique  Key_name  Seq_in_index  Column_name  Collation  Cardinality  Sub_part  Packed  Null  Index_type  Comment  Index_comment   
si_inventory 0 PRIMARY 1 domain_id A NULL NULL NULL  BTREE   
si_inventory 0 PRIMARY 2 id A 0 NULL NULL  BTREE   
si_inventory 1 product_id 1 product_id A NULL NULL NULL  BTREE   
si_inventory 1 quantity 1 quantity A NULL NULL NULL  BTREE   

Table  Non_unique  Key_name  Seq_in_index  Column_name  Collation  Cardinality  Sub_part  Packed  Null  Index_type  Comment  Index_comment   
si_invoice_items 0 PRIMARY 1 id A NULL NULL NULL  BTREE   
si_invoice_items 0 PRIMARY 2 invoice_id A 7 NULL NULL  BTREE   
si_invoice_items 1 unit_price 1 unit_price A NULL NULL NULL YES BTREE   
si_invoice_items 1 quantity 1 quantity A NULL NULL NULL  BTREE   
si_invoice_items 1 product_id 1 product_id A NULL NULL NULL YES  

如有任何建议,我们将不胜感激。

随着我上次的改变,进步了一点点

Query_time: 3.723339 Lock_time: 0.000254 Rows_sent: 100005 Rows_examined: 200024 Rows_affected: 0

SET timestamp=1455037952;
SELECT  
     A.id, 
     A.description,
     A.unit_price, 
     (SELECT coalesce(sum(B.quantity),0) from si_invoice_items B JOIN si_products A ON B.product_id = A.id) as qty_out ,
     (SELECT coalesce(sum(C.quantity),0) from si_inventory C JOIN si_products A ON C.product_id = A.id) as qty_in ,
     (SELECT coalesce(A.reorder_level,0)) as reorder_level ,
     (SELECT qty_in - qty_out ) as quantity,
     (CASE  WHEN A.enabled = 0 THEN 'Disabled' ELSE 'Enabled' END ) AS enabled
FROM 
    si_products A
WHERE 
    A.visible = 1
    AND A.domain_id = '1'

ORDER BY 
    description asc;

谢谢 Ollie,我已经尝试根据您的建议测试查询,但显然没有改善响应时间。

这是您的方法的结果:

# Query_time: 4.041339  Lock_time: 0.000245  Rows_sent: 100005  Rows_examined: 200029
# Rows_affected: 0
SET timestamp=1455045101;
SELECT p.id, p.description, p.unit_price,
    COALESCE(invoice.quantity,0) as qty_out,
    COALESCE(inventory.quantity,0)as  qty_in,
    coalesce(p.reorder_level,0) as reorder_level ,
    (select qty_in - qty_out ) as quantity

  FROM si_products p
  LEFT JOIN (
            SELECT SUM(quantity) quantity, product_id
                 FROM si_invoice_items 
                GROUP BY product_id
    ) invoice ON p.id = invoice.product_id
  LEFT JOIN (
            SELECT SUM(quantity) quantity, product_id
                 FROM si_inventory 
                GROUP BY product_id
    ) inventory ON p.id = inventory.product_id
 WHERE p.visible = 1
   AND p.domain_id = '1'

 ORDER BY            
         description asc;

最佳答案

您可以重构此查询以消除相关子查询(SELECT 子句中的嵌套 SELECT)。如果您将这些相关子查询替换为 JOINed 汇总子查询,您的性能可能会提高。

您似乎需要 si_invoice_itemssi_inventory 表的摘要。

您可以使用如下子查询获取这些摘要:

               SELECT SUM(quantity) quantity, product_id
                 FROM si_invoice_items 
                GROUP BY product_id

               SELECT SUM(quantity) quantity, product_id
                 FROM si_inventory 
                GROUP BY product_id

然后,您可以将这两个子查询视为虚拟表,并将它们连接到您的 si_products 表。请注意,您需要使用 LEFT JOIN,因为您的某些 si_products 行可能在其他表中没有匹配的行。

就像这样。

SELECT p.id, p.description, p.unit_price,
       COALESCE(invoice.quantity,0) qty_out,
       COALESCE(inventory.quantity,0) qty_in,
       etc, etc
  FROM si_products p
  LEFT JOIN (
               SELECT SUM(quantity) quantity, product_id
                 FROM si_invoice_items 
                GROUP BY product_id
       ) invoice ON p.id = invoice.product_id
  LEFT JOIN (
               SELECT SUM(quantity) quantity, product_id
                 FROM si_inventory 
                GROUP BY product_id
       ) inventory ON p.id = inventory.product_id
 WHERE p.visible = 1
   AND p.domain_id = '1'
 ORDER BY p.description asc;

这将在两个表上运行一次摘要,然后将它们连接起来。所以它应该运行得更快。

编辑您使用此查询获取的行数超过 100K 行。这是一个非常大的结果集,无论如何都需要一段时间。

您可以通过在库存和发票表的 (product_id, quahtity) 列上定义复合索引来加快汇总 (GROUP BY) 子查询的速度。

通过在 (visible, domain_id) 列上定义复合索引,您可以更快地从产品表中选择记录。

但是你的应用程序仍然需要处理十万行。

关于mysql - Mysql索引表查询慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35297917/

相关文章:

php - MySQL中如何计算时间差?

php - 单个 select 语句中的多个 GROUP_CONCAT

php - 在 PHP/Mysql 中单击按钮更新价格表

sql - 执行存储过程 NewId() 时语法不正确

php - laravel 无法将相同的值组合在一起

database - 甲骨文表格 : only iterate through selected records

database - Redis:以最少的 RAM 使用量识别多次出现的键

sql - 为什么这两个查询的性能差异如此之大?

mysql - 优化在同一个表上使用多个内连接的 SQL 查询

php - MYSQL 无法在不同的表上加载 OR 运算符