分页查询mysql + php需要20-40秒

时间:2018-01-16 22:05:45

标签: php mysql indexing

嗨我在我的应用程序中对角度js进行了分页,我将数据发送到包含用户设置的过滤器的大查询

UPDATE SQL_CALC_FOUND_ROWS这是我的问题。如何计算特定过滤器的行数。 10万行需要2秒钟我需要分页编号作为总数

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

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

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

行:50,000 用户表:4行 类表: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

如何让它更快?当我删除订单和SQL_CALC_FOUND_ROWS它更快但我需要它们 我听说过索引,但只有主键是索引

2 个答案:

答案 0 :(得分:1)

在推荐针对此查询的不同方法之前,很少有评论:

  • 您是否考虑删除SQL_CALC_FOUND_ROWS而是运行两个查询(一个计数,一个选择数据)?在某些情况下,它可能比将它们连接到一个查询更快。
  • 这些条件的目标是什么?你想要实现什么目标?我们可以删除它们(因为它们似乎总是会返回真实状态吗?) - AND DATE_FORMAT(st.date, '%H:%i') >= '00:00' AND DATE_FORMAT(st.date, '%H:%i') <= '23:59'
  • 您只需要10个结果,但数据库必须运行&#34;名称&#34;在LIMIT之前的每个结果的子查询(可能很多?)。因此,我建议将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

答案 1 :(得分:0)

先尝试一下:

INDEX(active, date)

user_idusers的PK吗? class_idclasses的PK吗?如果没有,那么它们应该是INDEXed

为什么要分开测试时间?

修复测试,以便明确每列所在的表格。

你真的需要LEFT JOIN吗?或者JOIN会满足吗?在后一种情况下,还有更多优化选项。

提供其他SELECTs的一些实际例子;可能需要不同的索引。

“第一”页面是否缓慢?还是只有以后的页面?有关分页优化的信息,请参阅this - not 使用OFFSET