将一个查询拆分为四个以避免大规模连接?

Hai*_*ood 4 php mysql optimization

所以我有一个看起来像这样的查询:

SELECT col1, col2, col3 ...
FROM action_6_members m
LEFT JOIN action_6_5pts f ON f.member_id = m.id
LEFT JOIN action_6_10pts t ON t.member_id = m.id
LEFT JOIN action_6_weekly w ON w.member_id = m.id
WHERE `draw_id` = '1' ORDER BY m.id DESC LIMIT 0, 20;
Run Code Online (Sandbox Code Playgroud)

现在这是一个大规模的加入(350万*4万*2万)

所以我的想法是:

SELECT * FROM action_6_members WHEREdraw_id= '1' ORDER BY id DESC LIMIT 0, 20;

然后循环使用php来构建 $in = "IN(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)";

然后运行
select * from action_6_5pts where member_id in $in
select * from action_6_10pts where member_id in $in
select * from action_6_weekly where member_id in $in

然后使用php将它们全部一起刷,

这意味着,虽然我使用四种不同的查询,但我只从每个查询中选择20行,而不是在所有查询中进行连接.

我会注意到一个重要的绩效奖金吗?


更新
所以,普遍的共识是,"不要这样做!"

这是应用程序的一般概述

它收到一个代码,

代码是5pt,10pt或每周代码,

所有三种代码类型都在单独的表中.这三个表有代码和member_id

member_id链接到action_6_members表中的id.

当声明代码时,数据被填入action_6_members表中.

然后该成员的ID被填充在表中对于被要求保护的代码.

上面的查询选择前20个成员.

所以我的问题是.

我该怎么做才能改善这一点?

因为目前所有内容都在查询完成之前超时.

action_6_members

CREATE TABLE `action_6_members` (
  `id` int(11) NOT NULL auto_increment,
  `draw_id` int(11) NOT NULL,
  `mobile` varchar(255) NOT NULL,
  `fly_buys` varchar(255) NOT NULL,
  `signup_date` datetime NOT NULL,
  `club` int(11) NOT NULL default '0' COMMENT '1 = yes, 2 = no',
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=1337 DEFAULT CHARSET=latin1
Run Code Online (Sandbox Code Playgroud)

action_6_ 5和10pts

CREATE TABLE `action_6_5pts` (
  `code` varchar(255) NOT NULL,
  `member_id` int(11) NOT NULL,
  PRIMARY KEY  (`code`),
  KEY `member_id` (`member_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
Run Code Online (Sandbox Code Playgroud)

action_6_weekly

CREATE TABLE `action_6_weekly` (
  `id` int(11) NOT NULL auto_increment,
  `code` varchar(255) NOT NULL,
  `member_id` int(11) NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `id` (`id`),
  KEY `member_id` (`member_id`)
) ENGINE=MyISAM AUTO_INCREMENT=3250001 DEFAULT CHARSET=latin1
Run Code Online (Sandbox Code Playgroud)


更新2:解释查询

id select_type table type possible_keys key       key_len ref  rows   Extra  
1  SIMPLE      m     ALL  \N            \N        \N      \N   1390   Using temporary; Using filesort  
1  SIMPLE      f     ALL  member_id     \N      \N      \N   36000  
1  SIMPLE      t     ALL  member_id     \N      \N      \N   18000  Using where  
1  SIMPLE      w     ref  member_id     member_id 4    m.id 525820 Using where  

最新加载数据从DB 7.26,4.60,2.45:刚刚经历过这样的

1.0是正常的最大负载......任何上述意味着它必须"爆发"并调用其他进程来处理.即7.26表示负载是刀片服务器最大值的7倍,并且不得不呼叫其他人来帮忙

所以目前这个查询不仅仅是一个怪物,它吃怪物作为小吃......

Nic*_*ght 7

作为一般规则,如果您的SQL查询可以完全模拟您想要做的事情,那么它可能比在特定范围内将其拆分为以PHP(或任何其他语言)粘合在一起的部分更快.

这些界限是:

  1. 对于这种情况,在MySQL中一定不能隐藏奇怪的病态行为.
  2. 您必须在所有必要的列上具有合理的索引.
  3. 没有(或不可能)你只能在PHP中合理地检测/处理你需要在中途中止查询的情况.
  4. 您的结果集在病理上并不大(例如,它适合内存并且不超过max_allowed_packetin 的大小my.cnf).

现在,这并没有解决您的SQL(或PHP中提议的替代实现)是否适合您正在做的事情,但只有在有关您的应用程序的功能以及您实际尝试的终点的更多信息时才能解决这个问题.到达.它可能没问题,也可能没有.


通过表格结构快速浏览一下您的更新,没有任何事情可以解决我可能造成大型性能问题的原因,但是:

  • 除非您确定需要,否则请勿使用MyISAM.InnoDB是你的朋友,特别是如果表有大量的写入流量.MyISAM的全桌锁可以真正咬你.拥有FOREIGN KEYS的参考完整性也会很好.
  • action_6_weeklyid作为PRIMARY KEY,以及UNIQUE KEY对... id.这是多余的.PRIMARY KEY实际上是一个超集UNIQUE KEY,你不需要创建一个单独的UNIQUE KEY.
  • EXPLAIN查询的输出会很有趣.