在mariadb中,相同数据库上的查询运行时间为0.4秒,在mysql 5.6、5.7和8中为83秒
我有一个在mysql上运行非常慢(83秒)但在mariadb上运行非常快的查询(.4秒) 我验证了数据数据库具有相同的索引和数据。Maria Db服务器的cpu(1VCPU)、内存(2gb)更少 Mysql服务器有8-32GB的ram和全四核处理器(尝试了5.6、5.7和8.0,结果类似) phppos_库存表约有170000行,phppos_物料表约有3000行 下面是查询和表,并进行了说明在mariadb中,相同数据库上的查询运行时间为0.4秒,在mysql 5.6、5.7和8中为83秒,mysql,mariadb,Mysql,Mariadb,我有一个在mysql上运行非常慢(83秒)但在mariadb上运行非常快的查询(.4秒) 我验证了数据数据库具有相同的索引和数据。Maria Db服务器的cpu(1VCPU)、内存(2gb)更少 Mysql服务器有8-32GB的ram和全四核处理器(尝试了5.6、5.7和8.0,结果类似) phppos_库存表约有170000行,phppos_物料表约有3000行 下面是查询和表,并进行了说明 SELECT /*+ SEMIJOIN(@subq MATERIALIZATION) */ SQL_C
SELECT /*+ SEMIJOIN(@subq MATERIALIZATION) */ SQL_CALC_FOUND_ROWS
1 AS _h,
`phppos_location_items`.`location_id` AS `location_id`,
`phppos_items`.`item_id`,
`phppos_items`.`name`,
`phppos_categories`.`id` AS `category_id`,
`phppos_categories`.`name` AS `category`,
`location`,
`company_name`,
`phppos_items`.`item_number`,
`size`,
`product_id`,
Coalesce(phppos_location_item_variations.cost_price,
phppos_item_variations.cost_price, phppos_location_items.cost_price,
phppos_items.cost_price, 0) AS cost_price,
Coalesce(phppos_location_item_variations.unit_price,
phppos_item_variations.unit_price, phppos_location_items.unit_price,
phppos_items.unit_price, 0) AS unit_price,
Sum(Coalesce(inv.trans_current_quantity, 0)) AS quantity,
Coalesce(phppos_location_item_variations.reorder_level,
phppos_item_variations.reorder_level, phppos_location_items.reorder_level,
phppos_items.reorder_level) AS reorder_level,
Coalesce(phppos_location_item_variations.replenish_level,
phppos_item_variations.replenish_level, phppos_location_items.replenish_level,
phppos_items.replenish_level) AS replenish_level,
description
FROM `phppos_inventory` `inv`
LEFT JOIN `phppos_items`
ON `phppos_items`.`item_id` = `inv`.`trans_items`
LEFT JOIN `phppos_location_items`
ON `phppos_location_items`.`item_id` = `phppos_items`.`item_id`
AND `phppos_location_items`.`location_id` = `inv`.`location_id`
LEFT JOIN `phppos_item_variations`
ON `phppos_items`.`item_id` = `phppos_item_variations`.`item_id`
AND `phppos_item_variations`.`id` = `inv`.`item_variation_id`
AND `phppos_item_variations`.`deleted` = 0
LEFT JOIN `phppos_location_item_variations`
ON `phppos_location_item_variations`.`item_variation_id` =
`phppos_item_variations`.`id`
AND `phppos_location_item_variations`.`location_id` =
`inv`.`location_id`
LEFT OUTER JOIN `phppos_suppliers`
ON `phppos_items`.`supplier_id` =
`phppos_suppliers`.`person_id`
LEFT OUTER JOIN `phppos_categories`
ON `phppos_items`.`category_id` = `phppos_categories`.`id`
WHERE inv.trans_id = (SELECT Max(inv1.trans_id)
FROM phppos_inventory inv1
WHERE inv1.trans_items = inv.trans_items
AND ( inv1.item_variation_id =
phppos_item_variations.id
OR phppos_item_variations.id IS NULL )
AND inv1.location_id = inv.location_id
AND inv1.trans_date < '2019-12-31 23:59:59')
AND inv.location_id IN( 1 )
AND `phppos_items`.`system_item` = 0
AND `phppos_items`.`deleted` = 0
AND `is_service` != 1
GROUP BY `phppos_items`.`item_id`
LIMIT 20
解释maria db:
+------+---------------------------------------------+-------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+--------------------+---------------------------------+--------+------------------------------+
| 1 | PRIMARY | phppos_items | ref | PRIMARY,deleted,deleted_system_item | deleted | 4 | const | 23955 | Using where |
| 1 | PRIMARY | inv | ref | phppos_inventory_ibfk_1,location_id,phppos_inventory_custom | phppos_inventory_ibfk_1 | 4 | freelance_pos5.phppos_items.item_id | 2 | Using where |
| 1 | PRIMARY | phppos_location_items | eq_ref | PRIMARY,phppos_location_items_ibfk_2 | PRIMARY | 8 | const,freelance_pos5.phppos_items.item_id | 1 | |
| 1 | PRIMARY | phppos_item_variations | eq_ref | PRIMARY,phppos_item_variations_ibfk_1 | PRIMARY | 4 | freelance_pos5.inv.item_variation_id | 1 | Using where |
| 1 | PRIMARY | phppos_location_item_variations | eq_ref | PRIMARY,phppos_item_attribute_location_values_ibfk_2 | PRIMARY | 8 | freelance_pos5.phppos_item_variations.id,const | 1 | Using where |
| 1 | PRIMARY | phppos_suppliers | ref | person_id | person_id | 4 | freelance_pos5.phppos_items.supplier_id | 1 | Using where |
| 1 | PRIMARY | phppos_categories | eq_ref | PRIMARY | PRIMARY | 4 | freelance_pos5.phppos_items.category_id | 1 | Using where |
| 2 | DEPENDENT SUBQUERY | inv1 | ref | phppos_inventory_ibfk_1,location_id,trans_date,phppos_inventory_ibfk_4,phppos_inventory_custom | phppos_inventory_custom | 8 | freelance_pos5.inv.trans_items,freelance_pos5.inv.location_id | 2 | Using where; Using index |
+------+--------------------+---------------------------------+--------+------------------------------------------------------------------------------------------------+-------------------------+---------+---------------------------------------------------------------+-------+--------------------------+
描述的表格(已达到StackOverflow字符限制)
创建表:
MYSQL(开发盒)
玛丽亚DB
MariaDB [freelance_pos5]> SHOW GLOBAL STATUS LIKE '%thread%';
+------------------------------------------+-------+
| Variable_name | Value |
+------------------------------------------+-------+
| Delayed_insert_threads | 0 |
| Performance_schema_thread_classes_lost | 0 |
| Performance_schema_thread_instances_lost | 0 |
| Slow_launch_threads | 0 |
| Threadpool_idle_threads | 0 |
| Threadpool_threads | 0 |
| Threads_cached | 3 |
| Threads_connected | 2 |
| Threads_created | 5 |
| Threads_running | 1 |
| wsrep_applier_thread_count | 0 |
| wsrep_rollbacker_thread_count | 0 |
| wsrep_thread_count | 0 |
+------------------------------------------+-------+
13 rows in set (0.00 sec)
MariaDB和MySQL的优化器在5.6版本开始出现显著差异。某些查询在其中一个查询中运行的速度比另一个查询快 我想我看到了一种加快查询速度的方法,也许在两个版本上都是如此
- 当与
相同时,不要使用连接
,这似乎至少适用于左连接
,该项目位于覆盖phppos_项目
的左
位置
- 请提供
;同时,我将猜测您有/没有哪些索引,以及每个表都有显示创建表
主键(id)
- 在适当的地方使用复合索引。(详见下文。)
- 在将连接到其余表之前获取20行:
SELECT ... FROM ( SELECT inv.id, pi.id FROM `phppos_inventory` AS inv `inv` JOIN `phppos_items` AS pi ON pi.`item_id` = `inv`.`trans_items` AND inv.location_id IN( 1 ) AND pi.`system_item` = 0 AND pi.`deleted` = 0 AND `is_service` != 1 -- Which table is this in??? GROUP BY pi.`item_id` LIMIT 20 ) LEFT JOIN .... (( all the other tables )) -- no GROUP BY or LIMIT needed (I think) phppos_items: INDEX(item_id, deleted, system_item, is_service) phppos_items: INDEX(deleted, system_item, is_service) phppos_inventory: INDEX(trans_items, location_id, location_id, item_variation_id, trans_date, trans_id) phppos_inventory: INDEX(location_id)
- 当与
相同时,不要使用连接
,这似乎至少适用于左连接
,该项目位于覆盖phppos_项目
的左
位置
- 请提供
;同时,我将猜测您有/没有哪些索引,以及每个表都有显示创建表
主键(id)
- 在适当的地方使用复合索引。(详见下文。)
- 在将连接到其余表之前获取20行:
SELECT ... FROM ( SELECT inv.id, pi.id FROM `phppos_inventory` AS inv `inv` JOIN `phppos_items` AS pi ON pi.`item_id` = `inv`.`trans_items` AND inv.location_id IN( 1 ) AND pi.`system_item` = 0 AND pi.`deleted` = 0 AND `is_service` != 1 -- Which table is this in??? GROUP BY pi.`item_id` LIMIT 20 ) LEFT JOIN .... (( all the other tables )) -- no GROUP BY or LIMIT needed (I think) phppos_items: INDEX(item_id, deleted, system_item, is_service) phppos_items: INDEX(deleted, system_item, is_service) phppos_inventory: INDEX(trans_items, location_id, location_id, item_variation_id, trans_date, trans_id) phppos_inventory: INDEX(location_id)
phppos\u inventory\u自定义索引进行索引范围扫描(ref
)。MySQL也选择了索引范围扫描,但超过了phppos\u inventory\u ibfk\u 1
然而,如果没有这两个索引的定义,很难评估引擎为什么选择了不同的路径
请在您的问题中添加这些索引的定义,以及它们的选择性(所选估计行的百分比/表总行数)以详细说明。除了由于外部联接被丢弃而导致查询产生误导之外,主要区别在于MariabDB中的第二个引擎操作是索引范围扫描(ref
)使用phppos_inventory_custom
索引。MySQL也选择了索引范围扫描,但选择了phppos_inventory_ibfk_1
然而,如果没有这两个索引的定义,很难评估引擎为什么选择了不同的路径
请在您的问题中添加这些索引的定义,以及它们的选择性(所选估计行的百分比/表总行数),以详细说明。移动
WHERE inv.trans_id = (SELECT Max(inv1.trans_id)
进入内部连接是游戏规则改变者
INNER JOIN (
SELECT inv1.trans_items, inv1.item_variation_id, inv1.location_id, MAX(inv1.trans_id) as trans_id
FROM phppos_inventory inv1
WHERE inv1.trans_date < '2019-12-31 23:59:59'
GROUP BY inv1.trans_items, inv1.item_variation_id, inv1.location_id
ORDER BY inv1.trans_items, inv1.item_variation_id, inv1.location_id
) inv1 on inv1.trans_id = inv.trans_id
AND inv1.trans_items = inv.trans_items
AND (inv1.item_variation_id = phppos_item_variations.id OR phppos_item_variations.id IS NULL)
AND inv1.location_id = inv.location_id
内部连接(
选择inv1.trans\u items、inv1.item\u variation\u id、inv1.location\u id、MAX(inv1.trans\u id)作为trans\u id
来自phppos_库存inv1
其中inv1.trans_日期<'2019-12-31 23:59:59'
按inv1.trans\u项目、inv1.item\u变体\u id、inv1.location\u id分组
按inv1.trans\u项目、inv1.item\u变体\u id、inv1.location\u id订购
)inv1.trans\U id上的inv1=inv.trans\U id
和inv1.trans\u项目=inv.trans\u项目
和(inv1.item_variation_id=phppos_item_variations.id或phppos_item_variations.id为空)
和inv1.location\u id=inv.location\u id
执行时间从80+s减少到~移动
WHERE inv.trans_id = (SELECT Max(inv1.trans_id)
进入内部连接是游戏规则改变者
INNER JOIN (
SELECT inv1.trans_items, inv1.item_variation_id, inv1.location_id, MAX(inv1.trans_id) as trans_id
FROM phppos_inventory inv1
WHERE inv1.trans_date < '2019-12-31 23:59:59'
GROUP BY inv1.trans_items, inv1.item_variation_id, inv1.location_id
ORDER BY inv1.trans_items, inv1.item_variation_id, inv1.location_id
) inv1 on inv1.trans_id = inv.trans_id
AND inv1.trans_items = inv.trans_items
AND (inv1.item_variation_id = phppos_item_variations.id OR phppos_item_variations.id IS NULL)
AND inv1.location_id = inv.location_id
内部连接(
选择inv1.trans\u items、inv1.item\u variation\u id、inv1.location\u id、MAX(inv1.trans\u id)作为trans\u id
来自phppos_库存inv1
其中inv1.trans_日期<'2019-12-31 23:59:59'
按inv1.trans\u项目、inv1.item\u变体\u id、inv1.location\u id分组
按inv1.trans\u项目、inv1.item\u变体\u id、inv1.location\u id订购
)inv1.trans\U id上的inv1=inv.trans\U id
和inv1.trans\u项目=inv.trans\u项目
和(inv1.item_variation_id=phppos_item_variations.id或phppos_item_variations.id为空)
和inv1.location\u id=inv.location\u id
执行时间从80+s减少到~您的查询是错误的。筛选谓词和phppos_items.system_item=0
会破坏外部联接,有效地将其转换为内部联接。接下来的两个谓词也是如此。首先修复此问题,然后我们可以对其进行优化。SHOW CREATE TABLE
比o与description
(也可以是较少的文本)相比,阅读索引顺序。选择有趣的delete
作为索引,而不是deleted\u system\u item
,因为我假设命名是顺序。听起来你有一个“使用MariaDB”作为解决方案:-)顺便问一下,哪个MariaDB版本?您有一个没有订单的限额
?有人告诉我,作为默认顺序的组已被弃用。Maria db 10.2.31您的发布结果是否可以显示全局状态,如“%thread%”;从MySQL和MariaDB服务器?连接lft=rgt每侧的数据类型和(长度)在t的描述中是否相同