描述
我有一个类似于以下的MySQL表:
CREATE TABLE `ticket` (
`ticket_id` int(11) NOT NULL AUTO_INCREMENT,
`ticket_number` varchar(30) DEFAULT NULL,
`pick1` varchar(2) DEFAULT NULL,
`pick2` varchar(2) DEFAULT NULL,
`pick3` varchar(2) DEFAULT NULL,
`pick4` varchar(2) DEFAULT NULL,
`pick5` varchar(2) DEFAULT NULL,
`pick6` varchar(2) DEFAULT NULL,
PRIMARY KEY (`ticket_id`)
) ENGINE=InnoDB AUTO_INCREMENT=19675 DEFAULT CHARSET=latin1;
我们还假设我们已经存储在DB中的以下值:
+-----------+-------------------+-------+-------+-------+-------+-------+-------+
| ticket_id | ticket_number | pick1 | pick2 | pick3 | pick4 | pick5 | pick6 |
+-----------+-------------------+-------+-------+-------+-------+-------+-------+
| 655 | 08-09-21-24-46-52 | 8 | 9 | 21 | 24 | 46 | 52 |
| 658 | 08-23-24-40-42-45 | 8 | 23 | 24 | 40 | 42 | 45 |
| 660 | 07-18-19-20-22-31 | 7 | 18 | 19 | 20 | 22 | 45 |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 19674 | 06-18-33-43-49-50 | 6 | 18 | 33 | 43 | 49 | 50 |
+-----------+-------------------+-------+-------+-------+-------+-------+-------+
现在,我的目标是根据ticket_number
字段中各自的值(每组6个元素,按-
分割,将表中的每个票证(自身除外)进行比较。 )。换句话说,例如,假设我将ticket_id = 655
与ticket_id = 658
进行比较,就其各自的ticket_number
字段中的元素而言,那么我会发现元素08
和{{ 1}}出现在两个集合中。如果我们现在将24
与ticket_id = 660
进行比较,那么我们认为只有一个巧合:ticket_id = 19674
。
我实际用于执行这些比较的是以下查询:
18
也就是说,首先我创建select A.ticket_id, A.ticket_number, P.ticket_id, P.ticket_number, count(P.ticket_number) as cnt from ticket A inner join ticket P on A.ticket_id != P.ticket_id
where
((A.ticket_number like concat("%", lpad(P.pick1,2,0), "%"))
+ (A.ticket_number like concat("%", lpad(P.pick2,2,0), "%"))
+ (A.ticket_number like concat("%", lpad(P.pick3,2,0), "%"))
+ (A.ticket_number like concat("%", lpad(P.pick4,2,0), "%"))
+ (A.ticket_number like concat("%", lpad(P.pick5,2,0), "%"))
+ (A.ticket_number like concat("%", lpad(P.pick6,2,0), "%")) > 3) group by A.ticket_id
having cnt > 5;
连接不同INNER JOIN
的所有行,然后将每个ticket_id
(P.pickX
)与X=[1..6]
进行比较结果A.ticket_number
操作,我计算两组之间的匹配数。
最后,在执行之后,我得到了这样的东西:
INNER JOIN
问题
问题在于我为+-------------+-------------------+-------------+-------------------+-----+
| A.ticket_id | A.ticket_number | P.ticket_id | P.ticket_number | cnt |
+-------------+-------------------+-------------+-------------------+-----+
| 8489 | 14-21-28-32-48-49 | 2528 | 14-21-33-45-48-49 | 6 |
| 8553 | 02-14-17-38-47-53 | 2364 | 02-30-38-44-47-53 | 6 |
| 8615 | 05-12-29-33-36-43 | 4654 | 12-21-29-33-36-37 | 6 |
| 8686 | 09-13-29-34-44-48 | 6038 | 09-13-17-29-33-44 | 6 |
| 8693 | 01-10-14-17-42-50 | 5330 | 01-10-37-42-48-50 | 6 |
| ... | ... | ... | ... | ... |
| 19195 | 05-13-29-41-46-51 | 5106 | 07-13-14-29-41-51 | 6 |
+-------------+-------------------+-------------+-------------------+-----+
的表执行此操作,导致更多的棕褐色1百万10476 rows
与ticket_number
进行比较,总共持续约172秒结束。这太慢了。
目标
我的目标是尽快完成执行,以便在不到一秒的时间内完成,因为这必须是实时的。
这可能吗?
答案 0 :(得分:1)
如果要保留当前结构,请将pick1..6更改为tinyint类型而不是varchar
如果签名,则TINYINT(1)将值保存在-128到128之间。然后你的查询就没有%
的结尾,这是导致运行缓慢的原因。
然后,这两个查询会给你相同的结果
select * FROM ticket where pick1 = '8';
select * FROM ticket where pick1 = '08';
这是sql结构:
CREATE TABLE `ticket` (
`ticket_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`ticket_number` varchar(30) DEFAULT NULL,
`pick1` tinyint(1) unsigned zerofill DEFAULT NULL,
`pick2` tinyint(1) unsigned zerofill DEFAULT NULL,
`pick3` tinyint(1) unsigned zerofill DEFAULT NULL,
`pick4` tinyint(1) unsigned zerofill DEFAULT NULL,
`pick5` tinyint(1) unsigned zerofill DEFAULT NULL,
`pick6` tinyint(1) unsigned zerofill DEFAULT NULL,
PRIMARY KEY (`ticket_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
我想,你甚至可以删除zerofill
如果这不起作用,请更改表格设计。
答案 1 :(得分:1)
数字有多大?看起来像50.如果答案是63或更少,那么将格式更改为:
所有6个数字都存储在一个SET ('0','1','2',...,'50')
中,并使用合适的操作来设置第n位。
然后,比较两个集合变为BIT_COUNT(x & y)
以找出多少匹配。一个简单的比较将测试相等性。
如果您的目标是查看表中是否已有特定的抽奖猜测,那么请对该列进行索引,以便查找速度很快。我不是指几分钟甚至几秒钟,而是几毫秒。即使是十亿行。
位算术可以用SQL或客户端语言完成。例如,要为(11,33,7)构建SET
,代码将为
INSERT INTO t SET picks = '11,33,7' -- order does not matter
这也可行:
... picks = (1 << 11) |
(1 << 33) |
(1 << 7)
一个简单的例子:
CREATE TABLE `setx` (
`picks` set('1','2','3','4','5','6','7','8','9','10') NOT NULL
) ENGINE=InnoDB;
INSERT INTO setx (picks) VALUES ('2,10,6');
INSERT INTO setx (picks) VALUES ('1,3,5,7,9'), ('2,4,6,8,10'), ('9,8,7,6,5,4,3,2,1,10');
SELECT picks, HEX(picks+0) FROM setx;
+----------------------+--------------+
| picks | HEX(picks+0) |
+----------------------+--------------+
| 2,6,10 | 222 |
| 1,3,5,7,9 | 155 |
| 2,4,6,8,10 | 2AA |
| 1,2,3,4,5,6,7,8,9,10 | 3FF |
+----------------------+--------------+
4 rows in set (0.00 sec)