【问题标题】:Very Slow result when use WHERE and ORDER BY condition in MYSQL Query在 MYSQL 查询中使用 WHERE 和 ORDER BY 条件时结果非常慢
【发布时间】:2019-03-25 02:16:05
【问题描述】:

我正面临结果非常缓慢的问题。

我也共享表结构和结果。

如果您有任何建议,请尽快更新。

================================================ =================== 表结构 --https://www.phpmyadmin.net/ -- -- 主机:本地主机: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;

提交;

显示第 0 - 24 行(总共 25586268 行,查询耗时 0.0007 秒。)

user_material中选择*

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

显示第 0 - 24 行(共 77 行,查询耗时 22.9434 秒。)

SELECT * FROM user_material where status='submitted'

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

显示第 0 - 24 行(总共 34026300 行,查询耗时 24.4978 秒。) [提交日期:... - ...]

SELECT * FROM user_material ORDER BYmitted_date ASC

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

如果您有任何建议,请更新我。

我在 yii2 框架中使用这个查询

【问题讨论】:

  • 请在您的问题中包含查询。
  • 请同时查询

标签: mysql sql performance sql-order-by where


【解决方案1】:

对于这个查询:

SELECT *
FROM user_material 
WHERE status = 'submitted';

您希望在user_material(status) 上建立索引。

对于这个查询:

SELECT *
FROM user_material
ORDER BY submitted_date ASC

您想要在user_material(submitted_date) 上建立索引。

在这两种情况下,附加列可以在索引中之后指定为第一列。我在您的架构中没有看到这些索引。

【讨论】:

  • 但是这些是列,状态有简单的文本,提交日期有日期。
  • 所以你建议我如何为这些 solumns 提供索引会更好
  • @LetsCMSPvtLtd 索引不仅适用于原始列 (int, bigint...),而且适用于 varchar 和 datetime 列。如果您想提高性能,请考虑将状态设置为 int 并将日期时间设置为 long
  • @Gordon Linoff,谢谢你的建议,我在表中的可搜索列上添加了索引,之后搜索工作速度非常快,而不是以前。你节省了我很多时间。谢谢
  • @MạnhQuyếtNguyễn - DATETIME 列有很多有用的功能;不要改太long(反正MySQL里没有这种数据类型)。
【解决方案2】:

除了@Gordon Linoff 的建议外,您还应该考虑进一步规范化您的表,以提高 SQL 的效率。对status_id 使用非常短的代码或int,并将状态代码和描述的唯一列表存储在查找表中。然后只需在您的 SQL 中加入查找表。有关规范化的详细说明,请参阅此article

我还建议更改time 列的列名或数据类型,因为这没有任何意义。什么时间值需要 255 个字符?

如果您关心性能,那么首先要关注的是从查询中删除不必要的字节、排序和过滤器。这种方法处理大多数性能问题。如何加入表格也很重要。随着数据量和复杂性的增加,调整工作也变得越来越复杂。

了解EXPLAIN 将有助于您的努力。有关详细信息,请参阅EXPLAIN documentation

-- 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;

查询现在看起来像这样:

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;

【讨论】:

    【解决方案3】:

    请试试这个。

    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'; 
    

    还可以在 where 和 order 字段上创建索引。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-02
      • 2021-07-16
      • 1970-01-01
      相关资源
      最近更新 更多