Mysql - 从200万行加速选择查询

时间:2017-12-04 12:39:12

标签: mysql query-optimization

我有一张如下表格,

Field    Type      Null Key Default               Extra

id       bigint(11) NO  PRI NULL                  auto_increment
deviceId bigint(11) NO  MUL NULL        
value    double     NO      NULL        
time    timestamp   YES MUL 0000-00-00 00:00:00 

它有超过200万行。当我跑select * from tableName;时需要超过15分钟。

当我运行select value,time from sensor_value where time > '2017-05-21 04:47:48' and deviceId>=812;加载时需要超过45秒。

注意: 512有超过92514行。 即使我为下面的列添加了索引,

ALTER TABLE `sensor_value` 
 ADD INDEX `IDX_FIELDS1_2` (`time`, `deviceId`) ;

如何快速选择查询?(在1秒内加载)我的索引编写错误吗?

2 个答案:

答案 0 :(得分:2)

只有4列?听起来你的RAM很少,或innodb_buffer_pool_size设置得太低。因此,您严重受I / O限制和/或交换。

WHERE time > '2017-05-21 04:47:48'
  AND deviceId >= 812

是两个范围。没有彻底的方法来优化它。这些都有帮助。如果你有两者,优化器可能选择更好的一个:

INDEX(time)
INDEX(deviceId)

在InnoDB中使用“辅助”索引时,查询首先查看索引BTree;当那里有匹配时,它必须在“数据”BTree中查找(使用PRIMARY KEY进行查找)。

您在尝试INDEX(time, deviceId)时看到的一些异常时间是因为过滤不必经常覆盖到数据中。

您是否将id用于除唯一性之外的任何其他内容?对装置是否是&时间独特?如果答案为“否”和“是”,则取消id并更改为PRIMARY KEY(deviceId, time)。或者你可以交换这两列。您还有其他疑问吗?

摆脱id会缩小表格,从而减少I / O.

答案 1 :(得分:1)

通常使用组合索引时,必须在第一列上使用相等运算符,然后可以在第二列上使用范围条件。因此,我建议您更改索引中的列顺序,如下所示:

ublic class TheMedicalResourceManagementSystem 
{
    JFrame jf;
    JPanel jp;
    JButton b;
    JTextField t;
    JTextField t2;

    public static void main(String[] args) 
    {
        TheMedicalResourceManagementSystem cc = new TheMedicalResourceManagementSystem();

       // SwingUtilities.invokeLater(() -> new GUI("The Medical Resource Management System").setVisible(true));   
    }

    public TheMedicalResourceManagementSystem()
    {



        jf = new JFrame("Frame");
        jp = new JPanel();
        jp.setLayout(new FlowLayout());
        jf.add(jp);
        t = new JTextField(15);
        jp.add(t);
           t2 = new JTextField(15);
        jp.add(t);
        jp.add(t2);

b= new JButton("Login");
jp.add(b);

        jf.setSize(200,200);
        jf.setVisible(true);

        String username = t.getText();
        String password = t2.getText();

         b.addActionListener((ActionEvent e) -> {
             if(username.equals("admin") && password.equals("password"))
             {
                 SwingUtilities.invokeLater(() -> new GUI("Medical Remote Management System").setVisible(true));
             }

             else
             {
                 JOptionPane.showMessageDialog( null, "Incorrect username or password , Please try again");
             }});

}


}

然后更改为ALTER TABLE `sensor_value` ADD INDEX `IDX_FIELDS1_2` (`deviceId`, `time`) ; 使用等号(使用deviceId而非deviceId=812):

deviceId>=812

我希望它可以提供帮助。

对于Mysql而言,200万条记录并不多,如果做正确的事情,10亿条记录的结果不到1秒是正常的。