草庐IT

mysql - 我怎样才能加快我的查询。子查询太慢

coder 2023-10-03 原文

我的查询是一个库存表。子查询连接所做的是获取每个库存 Assets 的工单总数。如果我使用设备类型、供应商、位置和房间的主要连接运行基本查询,它运行得很好。不到一秒返回结果。将它与子查询连接一起使用,需要 15 到 20 秒才能返回结果。

这是完整的查询:

SELECT `inventory`.inventory_id AS 'inventory_id', 
       `inventory`.media_tag AS 'media_tag', 
       `inventory`.asset_tag AS 'asset_tag', 
       `inventory`.idea_tag AS 'idea_tag', 
       `equipTypes`.equipment_type AS 'equipment_type',  
       `inventory`.equip_make AS 'equip_make', 
       `inventory`.equip_model AS 'equip_model', 
       `inventory`.equip_serial AS 'equip_serial', 
       `inventory`.sales_order AS 'sales_order', 
       `vendors`.vendor_name AS 'vendor_name', 
       `inventory`.purchase_order AS 'purchase_order', 
       `status`.status AS 'status', 
       `locations`.location_name AS 'location_name', 
       `rooms`.room_number AS 'room_number', 
       `inventory`.notes AS 'notes', 
       `inventory`.send_to AS 'send_to', 
       `inventory`.one_to_one AS 'one_to_one', 
       `enteredBy`.user_name AS 'user_name', 
       from_unixtime(`inventory`.enter_date, '%m/%d/%Y') AS 'enter_date', 
       from_unixtime(`inventory`.modified_date, '%m/%d/%Y') AS 'modified_date', 
       COALESCE(at.assets,0) AS assets 
FROM mod_inventory_data AS `inventory` 
LEFT JOIN mod_inventory_equip_types AS `equipTypes` 
       ON `equipTypes`.equip_type_id = `inventory`.equip_type_id 
LEFT JOIN mod_vendors_main AS `vendors`  
       ON `vendors`.vendor_id = `inventory`.vendor_id 
LEFT JOIN mod_inventory_status AS `status`  
       ON `status`.status_id = `inventory`.status_id 
LEFT JOIN mod_locations_data AS `locations`  
       ON `locations`.location_id = `inventory`.location_id 
LEFT JOIN mod_locations_rooms AS `rooms`  
       ON `rooms`.room_id = `inventory`.room_id 
LEFT JOIN mod_users_data AS `enteredBy`  
       ON `enteredBy`.user_id = `inventory`.entered_by
LEFT JOIN  
       ( SELECT asset_tag, count(*) AS assets 
         FROM mod_workorder_data 
         WHERE asset_tag IS NOT NULL 
         GROUP BY asset_tag ) AS at  
       ON at.asset_tag = inventory.asset_tag 
ORDER BY inventory_id ASC LIMIT 0,20

MySQL EXPLAIN 数据在这里

+----+-------------+--------------------+--------+---------------+-----------+---------+-------------------------------------+-------+---------------------------------+
| id | select_type | table              | type   | possible_keys | key       | key_len | ref                                 | rows  | Extra                           |
+----+-------------+--------------------+--------+---------------+-----------+---------+-------------------------------------+-------+---------------------------------+
|  1 | PRIMARY     | inventory          | ALL    | NULL          | NULL      | NULL    | NULL                                | 12612 | Using temporary; Using filesort |
|  1 | PRIMARY     | equipTypes         | eq_ref | PRIMARY       | PRIMARY   | 4       | spsd_woidbs.inventory.equip_type_id |     1 |                                 |
|  1 | PRIMARY     | vendors            | eq_ref | PRIMARY       | PRIMARY   | 4       | spsd_woidbs.inventory.vendor_id     |     1 |                                 |
|  1 | PRIMARY     | status             | eq_ref | PRIMARY       | PRIMARY   | 4       | spsd_woidbs.inventory.status_id     |     1 |                                 |
|  1 | PRIMARY     | locations          | eq_ref | PRIMARY       | PRIMARY   | 4       | spsd_woidbs.inventory.location_id   |     1 |                                 |
|  1 | PRIMARY     | rooms              | eq_ref | PRIMARY       | PRIMARY   | 4       | spsd_woidbs.inventory.room_id       |     1 |                                 |
|  1 | PRIMARY     | enteredBy          | eq_ref | PRIMARY       | PRIMARY   | 4       | spsd_woidbs.inventory.entered_by    |     1 |                                 |
|  1 | PRIMARY     | <derived2>         | ALL    | NULL          | NULL      | NULL    | NULL                                |  4480 |                                 |
|  2 | DERIVED     | mod_workorder_data | range  | asset_tag     | asset_tag | 13      | NULL                                | 15897 | Using where; Using index        |
+----+-------------+--------------------+--------+---------------+-----------+---------+-------------------------------------+-------+---------------------------------+

使用 MySql 查询分析我得到这个:

+--------------------------------+------------+
| Status                         | Time       |
+--------------------------------+------------+
| starting                       |  0.000020  | 
| checking query cache for query |  0.000263  |
| Opening tables                 |  0.000034  |
| System lock                    |  0.000013  |
| Table lock                     |  0.000079  |
| optimizing                     |  0.000011  |
| statistics                     |  0.000138  |
| preparing                      |  0.000019  |
| executing                      |  0.000010  |
| Sorting result                 |  0.000004  |
| Sending data                   |  0.015103  |
| init                           |  0.000094  |
| optimizing                     |  0.000009  |
| statistics                     |  0.000049  |
| preparing                      |  0.000022  |
| Creating tmp table             |  0.000104  |
| executing                      |  0.000009  |
| Copying to tmp table           | 15.410168  |
| Sorting result                 |  0.009488  |
| Sending data                   |  0.000215  |
| end                            |  0.000006  |
| removing tmp table             |  0.001997  |
| end                            |  0.000018  |
| query end                      |  0.000005  |
| freeing items                  |  0.000112  |
| storing result in query cache  |  0.000011  |
| removing tmp table             |  0.000022  |
| closing tables                 |  0.000036  |
| logging slow query             |  0.000005  |
| logging slow query             |  0.000005  |
| cleaning up                    |  0.000013  |
+--------------------------------+------------+

这表明瓶颈正在复制到临时表,但我不确定如何加快速度。我可以配置服务器端的设置以加快速度吗?是否可以对现有查询进行更改以产生更快的相同结果?

在我看来,LEFT JOIN 子查询每次都会给出相同的结果数据矩阵,因此如果它必须对 list 列表中的每一行运行该查询,我可以理解为什么它会很慢。或者MySQL在运行时是否缓存子查询?我以为我在某处读到 MySQL 不缓存子查询,这是真的吗?

感谢任何帮助。

最佳答案

这是我所做的,看起来效果不错。我创建了一个名为 mod_workorder_counts 的表。该表有两个字段,唯一的 Assets 标签,以及 wo_count 和 INT(3) 字段。我正在用这个查询填充该表:

INSERT INTO mod_workorder_counts ( asset_tag, wo_count ) 
select s.asset_tag, ct 
FROM
  ( SELECT t.asset_tag, count(*) as ct
    FROM mod_workorder_data t
    WHERE t.asset_tag IS NOT NULL
    GROUP BY t.asset_tag
  ) as s
ON DUPLICATE KEY UPDATE mod_workorder_counts.wo_count = ct

执行时间为 0.1580 秒,这可能会被认为稍微慢一点,但还不错。

现在,当我对原始查询运行此修改时:

SELECT `inventory`.inventory_id AS 'inventory_id', 
       `inventory`.media_tag AS 'media_tag', 
       `inventory`.asset_tag AS 'asset_tag', 
       `inventory`.idea_tag AS 'idea_tag', 
       `equipTypes`.equipment_type AS 'equipment_type',  
       `inventory`.equip_make AS 'equip_make', 
       `inventory`.equip_model AS 'equip_model', 
       `inventory`.equip_serial AS 'equip_serial', 
       `inventory`.sales_order AS 'sales_order', 
       `vendors`.vendor_name AS 'vendor_name', 
       `inventory`.purchase_order AS 'purchase_order', 
       `status`.status AS 'status', 
       `locations`.location_name AS 'location_name', 
       `rooms`.room_number AS 'room_number', 
       `inventory`.notes AS 'notes', 
       `inventory`.send_to AS 'send_to', 
       `inventory`.one_to_one AS 'one_to_one', 
       `enteredBy`.user_name AS 'user_name', 
       from_unixtime(`inventory`.enter_date, '%m/%d/%Y') AS 'enter_date', 
       from_unixtime(`inventory`.modified_date, '%m/%d/%Y') AS 'modified_date', 
       COALESCE(at.wo_count, 0) AS workorders 
FROM mod_inventory_data AS `inventory` 
LEFT JOIN mod_inventory_equip_types AS `equipTypes` 
       ON `equipTypes`.equip_type_id = `inventory`.equip_type_id 
LEFT JOIN mod_vendors_main AS `vendors`  
       ON `vendors`.vendor_id = `inventory`.vendor_id 
LEFT JOIN mod_inventory_status AS `status`  
       ON `status`.status_id = `inventory`.status_id 
LEFT JOIN mod_locations_data AS `locations`  
       ON `locations`.location_id = `inventory`.location_id 
LEFT JOIN mod_locations_rooms AS `rooms`  
       ON `rooms`.room_id = `inventory`.room_id 
LEFT JOIN mod_users_data AS `enteredBy`  
       ON `enteredBy`.user_id = `inventory`.entered_by
LEFT JOIN mod_workorder_counts AS at  
       ON at.asset_tag = inventory.asset_tag 
ORDER BY inventory_id ASC LIMIT 0,20

它在 0.0051 秒内执行。这使得两个查询之间的总时间为 0.1631 秒,接近 1/10 秒,而原始子查询为 15+ 秒。

如果我只是包含字段“wo_count”而不使用 COALESCE,我会得到“mod_workorder_counts”表中未列出的任何 Assets 标签的 NULL 值。因此,对于任何 NULL 值,COALESCE 都会给我一个 0,这正是我想要的。

现在我将对其进行设置,以便在为 Assets 标签输入工作订单时,我将在那时对计数表更新进行 INSERT/UPDATE 查询,这样它就不会不必要地运行。

关于mysql - 我怎样才能加快我的查询。子查询太慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5683351/

有关mysql - 我怎样才能加快我的查询。子查询太慢的更多相关文章

  1. ruby - ECONNRESET (Whois::ConnectionError) - 尝试在 Ruby 中查询 Whois 时出错 - 2

    我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.

  2. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  3. ruby-on-rails - 在 Rails 和 ActiveRecord 中查询时忽略某些字段 - 2

    我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr

  4. ruby-on-rails - 如果我将 ruby​​ 版本 2.5.1 与 rails 版本 2.3.18 一起使用会怎样? - 2

    如果我使用ruby​​版本2.5.1和Rails版本2.3.18会怎样?我有基于rails2.3.18和ruby​​1.9.2p320构建的rails应用程序,我只想升级ruby的版本,而不是rails,这可能吗?我必须面对哪些挑战? 最佳答案 GitHub维护apublicfork它有针对旧Rails版本的分支,有各种变化,它们一直在运行。有一段时间,他们在较新的Ruby版本上运行较旧的Rails版本,而不是最初支持的版本,因此您可能会发现一些关于需要向后移植的有用提示。不过,他们现在已经有几年没有使用2.3了,所以充其量只能让更

  5. ruby - 我可以将我的 README.textile 以正确的格式放入我的 RDoc 中吗? - 2

    我喜欢使用Textile或Markdown为我的项目编写自述文件,但是当我生成RDoc时,自述文件被解释为RDoc并且看起来非常糟糕。有没有办法让RDoc通过RedCloth或BlueCloth而不是它自己的格式化程序运行文件?它可以配置为自动检测文件后缀的格式吗?(例如README.textile通过RedCloth运行,但README.mdown通过BlueCloth运行) 最佳答案 使用YARD直接代替RDoc将允许您包含Textile或Markdown文件,只要它们的文件后缀是合理的。我经常使用类似于以下Rake任务的东西:

  6. jquery - 我的 jquery AJAX POST 请求无需发送 Authenticity Token (Rails) - 2

    rails中是否有任何规定允许站点的所有AJAXPOST请求在没有authenticity_token的情况下通过?我有一个调用Controller方法的JqueryPOSTajax调用,但我没有在其中放置任何真实性代码,但调用成功。我的ApplicationController确实有'request_forgery_protection'并且我已经改变了config.action_controller.consider_all_requests_local在我的environments/development.rb中为false我还搜索了我的代码以确保我没有重载ajaxSend来发送

  7. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  8. 怎样用一台手机做自媒体? - 2

    其实做自媒体的成本并不高,入门只需要一部手机即可!在手机上找视频素材、使用手机剪辑视频、最后使用手机发布视频作品获得收益!方法并不难,今天这期内容就来给粉丝们分享一种小方法,每天稳定收益100-300,抓紧点赞收藏!1、找素材(1)使用手机拍摄自己喜欢的经典段落,使用程序把文案内容提取出来(2)也可以在豆瓣、知乎、微博等网站中找一些自己需要的文案素材(3)把文案进行润色修改,可以加入一些自己的观点(4)视频素材可以使用软件中自带的素材,也可以在素材网站中下载完整版的素材2、文案配音(1)把复制好的文案直接导入小程序中(2)调整音色、音调后一键合成音频即可(3)可以选择自己朗读配音,需要花一点时

  9. 使用canal同步MySQL数据到ES - 2

    文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co

  10. sql - 查询忽略时间戳日期的时间范围 - 2

    我正在尝试查询我的Rails数据库(Postgres)中的购买表,我想查询时间范围。例如,我想知道在所有日期的下午2点到3点之间进行了多少次购买。此表中有一个created_at列,但我不知道如何在不搜索特定日期的情况下完成此操作。我试过:Purchases.where("created_atBETWEEN?and?",Time.now-1.hour,Time.now)但这最终只会搜索今天与那些时间的日期。 最佳答案 您需要使用PostgreSQL'sdate_part/extractfunction从created_at中提取小时

随机推荐