使用大表提高查询性能?

时间:2018-10-04 15:35:22

标签: mysql performance indexing mysql-workbench mysql-slow-query-log

我有一个名为“ roomlogs”的大表,其中有近100万个条目。 表的结构:

  

id-> PK

     

roomId-> varchar FK到Rooms表

     

userId-> varchar FK到用户表

     

enterTime->日期和时间

     

exitTime->日期和时间

     

状态->布尔

我以前在roomID上建立过索引,最近我在userId列上添加了一个索引。

因此,当我使用以下代码运行存储过程时,它将花费更多的时间,例如平均50秒。这不应该。

    DELIMITER ;;
    CREATE DEFINER=`root`@`%` PROCEDURE `enter_room`(IN pRoomId varchar(200), IN puserId varchar(50), IN ptime datetime, IN phidden int, pcheckid int, pexit datetime)

begin
    update roomlogs set 
          roomlogs.exitTime = ptime,
          roomlogs.`status` = 1  
       where 
              roomlogs.userId = puserId 
          and roomlogs.`status` = 0 
          and DATEDIFF(ptime,roomlogs.enterTime) = 0;

    INSERT into roomlogs 
      ( roomlogs.roomId,
        roomlogs.userId,
        roomlogs.enterTime,
        roomlogs.exitTime,
        roomlogs.hidden,
        roomlogs.checkinId ) 
      value
      ( pRoomId,
        userId,
        ptime,
        pexit,
        phidden,
        pcheckid);

    select * 
       from 
          roomlogs 
       where 
          roomlogs.id= LAST_INSERT_ID();
    end ;;
    DELIMITER ;

花费这么长时间的原因可能是什么?

  1. 我最近添加了一个索引,因此以前的行没有被索引。
  2. 目前没有任何索引的存储类型选择。我应该将其更改为B树吗?
  3. 在我的网站上,我同时在其他过程中获得20-30个同时调用,而该过程具有10-20个同时调用,该过程中的更新查询是否锁定?但是在MySQL.slow_logs表中,每个查询的锁_time显示为0。
  4. 此行为还有其他原因吗?

编辑:这是显示表:

CREATE TABLE `roomlogs` (
   `roomId` varchar(200) CHARACTER SET latin1 DEFAULT NULL,
   `userID` varchar(50) CHARACTER SET latin1 DEFAULT NULL,
   `enterTime` datetime DEFAULT NULL,
   `exitTime` datetime DEFAULT NULL,
   `id` int(11) NOT NULL AUTO_INCREMENT,
   `status` int(11) DEFAULT '0',
   `hidden` int(11) DEFAULT '0',
   `checkinId` int(11) DEFAULT '-1',
   PRIMARY KEY (`id`),
   KEY `RoomLogIndex` (`roomId`),
   KEY `RoomLogIDIndex` (`id`),
   KEY `USERID` (`userID`)
 ) ENGINE=InnoDB AUTO_INCREMENT=1064216 DEFAULT CHARSET=utf8

我还可以看到该查询每天运行的次数更多,例如每天100000次(几乎连续)。

SELECT count(*) from roomlogs where roomId=proomId and status='0';

由于此查询从同一张表中读取数据,因此InnoDB会阻塞或在更新查询上创建锁定,因为我可以看到,当以上存储的过程运行的次数更多时,此查询将花费更多的时间。

以下是MySQL变量的链接:https://docs.google.com/document/d/17_MVaU4yvpQfVDT83yhSjkLHsgYd-z2mg6X7GwvYZGE/edit?usp=sharing

1 个答案:

答案 0 :(得分:1)

roomlogs需要以下“复合”索引:

INDEX(userId, `status`, enterTime)
  

我最近添加了一个索引,因此以前的行没有被索引。

不是。添加INDEX会索引整个表。

默认索引类型为BTree;无需显式指定它。

  

过程中的更新查询是否锁定?

它执行某种形式的锁定。 autocommit的值是什么?您是否明确使用BEGINCOMMIT?表是ENGINE=InnoDB吗?请提供SHOW CREATE TABLE

  

每个查询的MySQL.slow_logs表_time锁定显示0。

您显示的INSERT似乎与UPDATE插入了同一行。也许您需要INSERT ... ON DUPLICATE KEY UPDATE ...

不要“隐藏函数中的索引列”;代替DATEDIFF(roomlogs.enterTime,NOW()) = 0

AND enterTime >= CURDATE()
AND enterTime  < CURDATE() + INTERVAL 1 DAY

这可以使索引得到更充分的利用。

KEY `RoomLogIndex` (`roomId`),  Change to  (roomId, status)
KEY `RoomLogIDIndex` (`id`),    Remove, redundant with the PK

仅缓冲97,517,568的缓冲池-使它更像9G。