php - 分页查询mysql+php耗时20-40秒

标签 php mysql indexing

您好,我的应用程序中有 Angular JS 分页,我将数据发送到我的大查询,其中包括用户设置的过滤器

更新 SQL_CALC_FOUND_ROWS 这是我的问题。如何计算特定过滤器的行数。 100,000 行花了我 2 秒我需要分页数作为总数

更新: 我在这里错过了以下内部查询:

(从学生中选择 count(*) 作为inner_st,其中 st.name = inner_st.name)作为姓名,

当我删除上面的内部查询时速度要快得多

行数:50,000 用户表:4行 类(class)表:4行 索引:仅 id 作为主键

查询时间20-40秒

tables: students.

columns : id, date ,class, name,image,status,user_id,active 

table user
coloumn: id,full_name,is_admin

查询

SELECT  SQL_CALC_FOUND_ROWS st.id, 
        st.date,
        st.image,
        st.user_id,
        st.status,
        st, 
        ck.name AS class_name,
        users.full_name,
        (select count(*) from students AS inner_st where st.name = inner_st.name) AS names,
FROM students AS st
    LEFT JOIN  users ON st.user_id = users.user_id
    LEFT JOIN  classes AS ck  ON st.class = ck.id
WHERE date BETWEEN '2018-01-17' AND DATE_ADD('2018-01-17', INTERVAL 1 DAY)
    AND DATE_FORMAT(date,'%H:%i') >= '00:00'
    AND DATE_FORMAT(date,'%H:%i') <= '23:59'
    AND st.active=1 
    -- here I can concat filters from  web like "and class= 1"
ORDER BY st.date DESC
LIMIT  0, 10

怎样才能让它更快?当我删除 order by 和 SQL_CALC_FOUND_ROWS 时速度更快,但我需要它们 我听说过索引,但只有主键是索引

最佳答案

在推荐对此查询的不同方法之前,有一些评论:

  • 您是否考虑删除 SQL_CALC_FOUND_ROWS而是运行两个查询(一个用于计数,一个用于选择数据)?在某些情况下,这可能比将它们连接到一个查询更快。
  • 这些条件的目标是什么?你想达到什么目的?我们可以删除它们吗(因为它们似乎总是返回 true?)- AND DATE_FORMAT(st.date, '%H:%i') >= '00:00' AND DATE_FORMAT(st.date, '%H:%i') <= '23:59'
  • 您只需要 10 个结果,但数据库必须为 LIMIT 之前的每个结果运行“names”子查询(这可能很多?)。因此,我建议将 SELECT 子句中的子查询提取到临时表,为其建立索引并连接到它(请参阅下面的固定查询)。

为了优化查询,我们首先添加这些索引:

ALTER TABLE `classes` ADD INDEX `classes_index_1` (`id`, `name`);
ALTER TABLE `students` ADD INDEX `students_index_1` (`active`, `user_id`, `class`, `name`, `date`);
ALTER TABLE `users` ADD INDEX `users_index_1` (`user_id`, `full_name`);

现在创建临时表(最初这是 SELECT 子句中的子查询)并为其建立索引:

-- Transformed subquery to a temp table to improve performance
CREATE TEMPORARY TABLE IF NOT EXISTS temp1 AS SELECT
        count(*) AS names,
        name 
    FROM
        students AS inner_st 
    WHERE
        1 = 1 
    GROUP BY
        name 
    ORDER BY
        NULL

-- This index is required for optimal temp tables performance
ALTER TABLE
  `temp1`
ADD
  INDEX `temp1_index_1` (`name`, `names`);

修改后的查询:

SELECT
        SQL_CALC_FOUND_ROWS st.id,
        st.date,
        st.image,
        st.user_id,
        st.status,
        ck.name AS class_name,
        users.full_name,
        temp1.names 
    FROM
        students AS st 
    LEFT JOIN
        users 
            ON st.user_id = users.user_id 
    LEFT JOIN
        classes AS ck 
            ON st.class = ck.id 
    LEFT JOIN
        temp1 
            ON st.name = temp1.name 
    WHERE
        st.date BETWEEN '2018-01-17' AND DATE_ADD('2018-01-17', INTERVAL 1 DAY) 
        AND st.active = 1 
    ORDER BY
        st.date DESC LIMIT 0,
        10

关于php - 分页查询mysql+php耗时20-40秒,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48290586/

相关文章:

MySQL 错误 #1064 靠近 UNION 版本 : 5. 5.27

php - 自动创建 MySQL 表 [用户控制]

php - Doctrine/Symfony2 中的 JMSSerializerBundle、SoftDeleteable 和多对多

mysql - 如何使用 python 与 MySQL 服务器上的其他客户端连接进行通信?

mysql - 我无法弄清楚我在进行此 MYSQL 查询时犯了什么错误

Delphi SetLength 自定义索引

python - 在现有数据帧上添加多级索引

mongodb - MongoDB 在使用 $exists 运算符检查字段是否存在时可以使用索引吗?

php - 将 session 数组中的购物车项目添加到 mysql 数据库

PHP - 在类中定义常量