简体   繁体   English

在MYSQL查询中使用WHERE和ORDER BY条件时结果非常慢

[英]Very Slow result when use WHERE and ORDER BY condition in MYSQL Query

I am facing issue of very slow result. 我面临的问题非常缓慢。

I am sharing table structure as and results also. 我正在分享表结构和结果。

if you have any suggestion please update soon if possible for you. 如果您有任何建议,请尽快更新。

================================================================= Table Structure -- https://www.phpmyadmin.net/ -- -- Host: localhost:3306 -- Generation Time: Mar 25, 2019 at 11:48 AM -- Server version: 5.5.61-cll -- PHP Version: 7.2.7 ================================================== =============== 表结构 - https://www.phpmyadmin.net/ - - 主机:localhost:3306 - 世代时间:2019年3月25日11:上午48点 - 服务器版本:5.5.61-cll - PHP版本:7.2.7

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";

--
-- Database: `energe3c_lms`
--

-- --------------------------------------------------------

--
-- Table structure for table `user_material`
--

CREATE TABLE `user_material` (
  `id` int(11) NOT NULL,
  `user_course_id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `material_id` int(11) NOT NULL,
  `attempt` int(11) NOT NULL,
  `another_attempt` tinyint(1) DEFAULT '0',
  `status` varchar(255) DEFAULT NULL,
  `complete` tinyint(1) DEFAULT NULL,
  `percent` float DEFAULT '0',
  `time` varchar(255) DEFAULT NULL,
  `marking_time` varchar(255) DEFAULT NULL,
  `marked_by` int(11) DEFAULT NULL,
  `feedback` text,
  `submitted_date` datetime DEFAULT NULL,
  `marking_date` datetime DEFAULT NULL,
  `created` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--
-- Indexes for dumped tables
--

--
-- Indexes for table `user_material`
--
ALTER TABLE `user_material`
  ADD PRIMARY KEY (`id`),
  ADD KEY `user_material-user` (`user_id`),
  ADD KEY `user_material-material` (`material_id`),
  ADD KEY `user_material-marking-user` (`marked_by`),
  ADD KEY `user_course-user_material` (`user_course_id`);

--
-- AUTO_INCREMENT for dumped tables
--

--
-- AUTO_INCREMENT for table `user_material`
--
ALTER TABLE `user_material`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;

--
-- Constraints for dumped tables
--

--
-- Constraints for table `user_material`
--
ALTER TABLE `user_material`
  ADD CONSTRAINT `user_course-user_material` FOREIGN KEY     (`user_course_id`) REFERENCES `user_course` (`id`) ON DELETE CASCADE ON     UPDATE CASCADE,
  ADD CONSTRAINT `user_material-marking-user` FOREIGN KEY (`marked_by`) REFERENCES `user` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
  ADD CONSTRAINT `user_material-material` FOREIGN KEY (`material_id`) REFERENCES `material` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  ADD CONSTRAINT `user_material-user` FOREIGN KEY (`user_id`)     REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;

COMMIT; 承诺;

Showing rows 0 - 24 (25586268 total, Query took 0.0007 seconds.) 显示行0 - 24(总计25586268,查询耗时0.0007秒。)

SELECT * FROM user_material SELECT * FROM user_material

================================================================= ================================================== ===============

Showing rows 0 - 24 (77 total, Query took 22.9434 seconds.) 显示0到24行(共77行,查询占用22.9434秒。)

SELECT * FROM user_material where status='submitted' SELECT * FROM user_material where status ='submitted'

================================================================= ================================================== ===============

Showing rows 0 - 24 (34026300 total, Query took 24.4978 seconds.) [submitted_date: ... - ...] 显示行0 - 24(总计34026300,查询占用24.4978秒。)[submitted_date:... - ...]

SELECT * FROM user_material ORDER BY submitted_date ASC SELECT * FROM user_material ORDER BY submitted_date ASC

================================================================= ================================================== ===============

If You have any suggestion, please update me. 如果您有任何建议,请更新我。

I am using this query in yii2 framework 我在yii2框架中使用此查询

For this query: 对于此查询:

SELECT *
FROM user_material 
WHERE status = 'submitted';

You want an index on user_material(status) . 您需要user_material(status)的索引。

For this query: 对于此查询:

SELECT *
FROM user_material
ORDER BY submitted_date ASC

You want an index on user_material(submitted_date) . 您想要user_material(submitted_date)上的索引。

In both these cases, additional columns can be in the index after the one specified as the first column. 在这两种情况下,在指定为第一列的索引之后 ,其他列可以位于索引中。 I do not see these indexes in your schema. 我没有在您的架构中看到这些索引。

Adding to the recommendation from @Gordon Linoff, you should consider normalizing your table further, to make the SQL more efficient. 添加@Gordon Linoff的建议,你应该考虑进一步规范你的表,以提高SQL的效率。 Use an very short code or int for status_id and store a unique list of status codes and descriptions in a lookup table. status_id使用非常短的代码或int ,并在查找表中存储唯一的状态代码和描述列表。 Then simply join the lookup table in your SQL. 然后只需在SQL中加入查找表即可。 See this article for a detailed explanation on normalization. 有关规范化的详细说明,请参阅此文章

I also recommend either changing the column name or the data type for the time column, because it doesn't make sense. 我还建议更改列名称或time列的数据类型,因为它没有意义。 What time value requires 255 characters? 什么时间值需要255个字符?

If you are concerned about performance, then the first thing to focus your attention on is removing unnecessary bytes, sorts and filters from your query. 如果您担心性能,那么首先要关注的是从查询中删除不必要的字节,排序和过滤器。 This approach deals with most performance issues. 此方法可处理大多数性能问题。 How you join tables is important as well. 如何连接表格也很重要。 As the data volume and complexity increases, the tuning effort becomes increasingly more complex as well. 随着数据量和复杂性的增加,调优工作也变得越来越复杂。

Getting to know EXPLAIN will help your effort. 了解EXPLAIN将有助于您的努力。 Refer to the EXPLAIN documentation for more information. 有关更多信息,请参阅EXPLAIN文档

-- Create your lookup table first
CREATE TABLE `material_status` (
  `id` int(11) NOT NULL,
  `status` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ALTER TABLE `material_status`
  ADD PRIMARY KEY (`id`),

ALTER TABLE `material_status`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;

-- Then create your user_material table
CREATE TABLE `user_material` (
  `id` int(11) NOT NULL,
  `user_course_id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `material_id` int(11) NOT NULL,
  `attempt` int(11) NOT NULL,
  `another_attempt` tinyint(1) DEFAULT '0',
  `status_id` int(11) DEFAULT NULL,
  `complete` tinyint(1) DEFAULT NULL,
  `percent` float DEFAULT '0',
  `time` varchar(255) DEFAULT NULL,
  `marking_time` varchar(255) DEFAULT NULL,
  `marked_by` int(11) DEFAULT NULL,
  `feedback` text,
  `submitted_date` datetime DEFAULT NULL,
  `marking_date` datetime DEFAULT NULL,
  `created` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- Create your extra index here
CREATE INDEX ix-submitted_date ON user_material(submitted_date);

-- Add the status to the keys and constraints
ALTER TABLE `user_material`
  ADD PRIMARY KEY (`id`),
  ADD KEY `user_material-user` (`user_id`),
  ADD KEY `user_material-material` (`material_id`),
  ADD KEY `user_material-marking-user` (`marked_by`),
  ADD KEY `user_course-user_material` (`user_course_id`),
  ADD KEY `user_material-status` (`status_id`);

ALTER TABLE `user_material`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;

ALTER TABLE `user_material`
  ADD CONSTRAINT `user_course-user_material` FOREIGN KEY (`user_course_id`) REFERENCES `user_course` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  ADD CONSTRAINT `user_material-marking-user` FOREIGN KEY (`marked_by`) REFERENCES `user` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
  ADD CONSTRAINT `user_material-material` FOREIGN KEY (`material_id`) REFERENCES `material` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  ADD CONSTRAINT `user_material-user` FOREIGN KEY (`user_id`)     REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  ADD CONSTRAINT `user_material-status` FOREIGN KEY (`status_id`) REFERENCES `material_status` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;

The queries will now look like this: 查询现在看起来像这样:

SELECT
um.id,
um.user_course_id,
um.user_id,
um.material_id,
um.attempt,
um.another_attempt,
ms.status,
um.complete,
um.percent,
um.time,
um.marking_time,
um.marked_by,
um.feedback,
um.submitted_date,
um.marking_date,
um.created
FROM user_material um
INNER JOIN material_status ms on ms.id = um.status_id
WHERE ms.status = 'submitted';

SELECT
um.id,
um.user_course_id,
um.user_id,
um.material_id,
um.attempt,
um.another_attempt,
ms.status,
um.complete,
um.percent,
um.time,
um.marking_time,
um.marked_by,
um.feedback,
um.submitted_date,
um.marking_date,
um.created
FROM user_material um
INNER JOIN material_status ms on ms.id = um.status_id
ORDER BY um.submitted_date ASC;

Please try this. 请试试这个。

SELECT
um.id,
um.user_course_id,
um.user_id,
um.material_id,
um.attempt,
um.another_attempt,
ms.status,
um.complete,
um.percent,
um.time,
um.marking_time,
um.marked_by,
um.feedback,
um.submitted_date,
um.marking_date,
um.created
FROM user_material um
INNER JOIN material_status ms on ms.id = um.status_id
AND ms.status = 'submitted'; 

And also create indexing on where and order field. 并且还在where和order字段上创建索引。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM