如何加快4路SQLITE内部联接的速度,尽管覆盖了所有表上的索引,但它仍然很慢

问题描述 投票:0回答:1

我有4个表需要很长时间才能加入SQLITE(版本3.31.1)。这是所涉及的5个表的简化视图(第一个“对象”未直接在连接中使用):

Table Objects:
    Objects.Id

Table Dates:  # Each day has 2 different values of date, some tables refer to one, some to the other
    Dates.Date_cal1  # Calendar 1
    Dates.Date_cal2  # Calendar 2

Table A:
    A.Object_Id
    A.Date_c1
    A.Value_A

Table B:
    B.Object_Id
    B.Date_c1
    B.Value_B

Table C:
    C.Object_Id
    C.Date_c2
    C.Value_C

(Object_id,Date)对构成每个A / B / C的主键。我正在运行的查询是这样的:

SELECT Dates.Date_cal1, A.Value_A, B.Value_B, C.Value_C
    FROM Dates
    INNER JOIN A ON A.Date_c1 = Dates.Date_cal1
    INNER JOIN B ON B.Date_c1 = Dates.Date_cal1 AND B.Object_Id = A.Object_Id
    INNER JOIN C ON C.Date_c2 = Dates.Date_cal2 AND C.Object_Id = A.Object_Id
    WHERE A.Object_Id=14
ORDER BY Dates.Date_cal1 ASC;

查询大约需要1-2分钟才能运行。一些注意事项:

  1. 我知道其中一些看起来很愚蠢(例如,A和B可以如此处所示合并)。只需假设真实情况有所有原因即可。
  2. 我有4个表的索引:日期同时具有(Date_cal1,Date_Cal2)和(Date_cal2,Date_cal1),并且A和B和C均由(Object_Id,Date_c *,Value_ *)排序,其中*为1 -or-2和A-or-B-or-C)。
  3. [在大小上,日期具有360行,A和B具有360万行,C具有1亿个(C较大,因为“ cal2”是更细的日历-您可以将其视为cal1每月一次) ,cal2每天一次)。
  4. 数据是非常规则的,这意味着10k object_id中的每一个在A / B / C中使用大约相等的行数。

当我为上面的查询运行EXPLAIN QUERY PLAN时,我得到:

QUERY PLAN
|--SEARCH TABLE B USING COVERING INDEX B_index (Object_Id=?)
|--SEARCH TABLE A USING PRIMARY KEY (Date_c1=? AND Object_Id=?)
|--SEARCH TABLE Dates USING PRIMARY KEY (Date_cal1=?)
|--SEARCH TABLE C USING PRIMARY KEY (Date_c2=? AND Object_Id=?)
`--USE TEMP B-TREE FOR ORDER BY

注意,只有第一部分提到利用覆盖指数。我不确定1分钟是否合理,但是我希望充分利用覆盖率索引将意味着A / B / C的日期和object_id过滤会更快(因为Object_Id = 14, A和B中总共有360行,C中总共有11k行)。

感谢任何人可以提供的任何帮助!

mysql sql sqlite query-optimization inner-join
1个回答
0
投票

首先,我将查询写为:

FROM Dates JOIN
     A
     ON A.Date_c1 = Dates.Date_cal1 JOIN
     B
     ON B.Date_c1 = A.Date_c1 AND
        B.Object_Id = A.Object_Id JOIN
     C
     ON C.Date_c2 = Dates.Date_cal2 AND C.Object_Id = A.Object_Id
WHERE A.Object_Id = 14

我建议在以下位置建立索引:

  • A(ObjectId, Date_c1)
  • B(Object_Id, Date_c1)
  • Dates(Date_cal1, Date_cal2)
  • C(Objet_Id Date_C2)

这应允许where子句使用索引过滤数据,而其余的联接也使用索引。

© www.soinside.com 2019 - 2024. All rights reserved.