【问题标题】:Mysql query still to slow for 100 million records in 10gb database size with index对于 10gb 数据库大小和索引的 1 亿条记录,Mysql 查询仍然很慢
【发布时间】:2019-06-14 02:45:36
【问题描述】:

我有一个相当庞大的产品和用户数据集以及他们的使用时间。

大约有 1 亿行,占用大约 10 GB 的磁盘空间。

数据集按以下顺序排列:

userid     itemid      purchase_date    
1             1          2018-12-22
11            1          2018-12-22
11            4          2018-12-22
12            4          2018-12-22
11            5          2018-12-22

.......100M+ rows.....

我也加了这样的索引,

ALTER TABLE purchase_data ADD INDEX (userid);
ALTER TABLE purchase_data ADD INDEX (itemid);
ALTER TABLE purchase_data ADD INDEX (purchase_date);

假设我想找到所有购买了产品(项目 1)的用户,然后找到他购买的所有其他项目。

Select itemid from purchase_data
    where userid in (Select userid, from purchase_data
                    where itemid=1)
      and itemid!=1

此查询需要永远运行。

其次,我还想将用户 ID 11 4 和用户 ID 12 也带来了 4 等用户之间的所有常见项目相加,所以我想将 4 与计数 2 相加

我为此写了一个类似的查询:

Select itemid,count(*) from purchase_data
    where userid in (Select userid, from purchase_data
                      where itemid=1)
      and itemid!=1
    group by itemid
    having count(itemid)>=1

这个脚本也需要无限的时间。

请帮忙,

谢谢

【问题讨论】:

  • 您能否发布这些查询的 EXPLAIN 结果?顺便说一句,第一个有错字,子查询中的“user_id”后面有一个“,”。
  • 您确认数据库确实使用了索引吗? EXPLAIN <query>.. 建立索引确实意味着数据库应该使用它.. 除了计算索引选择性以查看索引是否有意义Select COUNT(DISTINCT itemid)/COUNT(*) AS index_selectivity from purchase_data,理想情况下它应该是接近 1 的值
  • 存在语法错误。你遗漏了什么重要的东西吗?

标签: mysql database mariadb query-optimization semi-join


【解决方案1】:

你应该使用内连接而不是 IN 子句,例如:

Select itemid 
from purchase_data  a 
INNER JOIN  (
    Select userid
     from purchase_data where itemid=1
    ) T on t.userid = a,userid 
  where a.itemid != 1 

一个 IN 子句用作多个 OR 条件,而内部连接用作单个关系..

并且 您应该删除这些索引,而不是一列的多个索引,并创建一个复合索引,左侧是连接条件所涉及的列,右侧是其他列

create index my_idx on  purchase_data(userid, itemid );

分组查询也是如此

Select itemid , count(*)
from purchase_data  a 
INNER JOIN  (
    Select userid
     from purchase_data where itemid=1
    ) T on t.userid = a,userid 
  where itemid != 1 
group by itemid 
having count(itemid)>=1

【讨论】:

  • 删除单个索引并用这个复合索引替换它们可能会使事情变得更糟。 RDBMS 需要检查表两次:一次使用谓词itemid = 1,一次使用谓词t.user_id=a.user_ida.itemid !=1。第一个绝对不会从您建议的索引中受益,第二个可能会,尽管这可能只是因为包含该列并避免了书签查找。 !=1 不会排除太多行,我们需要去获取 itemid (除非这是 PK 在这种情况下(至少在 MSSQL 中)它被隐式包含)
猜你喜欢
  • 2021-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-13
  • 2017-08-12
  • 1970-01-01
  • 2011-12-13
  • 1970-01-01
相关资源
最近更新 更多