MySQL分区(innoDB) - 大表

时间:2017-01-15 11:05:06

标签: mysql performance innodb partitioning

我有一个MySQL非常大的数据库(10亿行),如下所示:

数据库:产品("名称","特征")

两列都是VARCHAR(50)。

实际上,它没有KEY sat,但" name"将是独特的,所以我想我会改变它" name"首要的关键。 (我之前应该这样做..现在我需要在添加primary_key选项之前执行删除重复查询)

我的问题是,当对表执行简单查询时,字面上需要很长时间。

SELECT caracteristics WHERE name=blabla LIMIT 1; //需要很长时间。

我正在考虑对现有表进行分区。

所以这就是问题:

  • 解决我的性能问题是个好主意吗?
  • 我怎样才能实现这一目标?
  • 我对ALTER TABLE的想法是设置' name'作为PRIMARY_KEY的专栏也是一个好主意吗?

  • 还有关于重复的查询,我在这里找到了这个,我做得对吗? (不要弄乱我的桌子......)

delete a
from products a
left join(
select max(name) maxname, caracteristics
from products
group by caracteristics) b
on a.name = maxname and
a.caracteristics= b.caracteristics
where b.maxname IS NULL;

3 个答案:

答案 0 :(得分:3)

我认为分区不是你应该针对这个特定问题的方式。你会怎么分区?按什么标准?

我认为您的主要关注点是架构,应该在其他任何事情之前修复:唯一记录不是唯一的。

由于容量测量,我认为任何解决方案都需要一段时间才能执行。但我敢打赌,这是最快的:

CREATE TABLE products_unique (
 name VARCHAR(50) NOT NULL,
 characteristics VARCHAR(50),
 PRIMARY KEY (name)
);

INSERT IGNORE INTO products_unique SELECT * FROM products;

RENAME TABLE products TO products_backup;
RENAME TABLE products_unique TO products;

副本将被任意显示,但我认为无论如何它都是你正在寻找的。 如果它需要太长时间,你应该尝试在一夜之间运行...我只希望事务缓冲区不会爆炸你在这种情况下我们必须处理一些存储过程来批量分离插入。

答案 1 :(得分:3)

您还可以使用忽略选项直接设置 PRIMARY KEY ,如下所示:

ALTER IGNORE TABLE `products` ADD PRIMARY KEY(name);

这将从名称中删除所有重复项。

<强>样品

MariaDB [l]> CREATE TABLE `products` (
    ->   `name` varchar(50) NOT NULL DEFAULT '',
    ->   `caracteristics` varchar(50) DEFAULT NULL
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.02 sec)

MariaDB [l]> INSERT INTO `products` (`name`, `caracteristics`)
    -> VALUES
    ->     ('val1', 'asdfasdfasdf'),
    ->     ('val2', 'asdasDasd'),
    ->     ('val3', 'aesfawfa'),
    ->     ('val1', '99999999');
Query OK, 4 rows affected (0.01 sec)
Records: 4  Duplicates: 0  Warnings: 0

MariaDB [l]> select * from products;
+------+----------------+
| name | caracteristics |
+------+----------------+
| val1 | asdfasdfasdf   |
| val2 | asdasDasd      |
| val3 | aesfawfa       |
| val1 | 99999999       |
+------+----------------+
4 rows in set (0.00 sec)

MariaDB [l]> ALTER IGNORE TABLE `products` ADD PRIMARY KEY(name);
Query OK, 4 rows affected (0.03 sec)
Records: 4  Duplicates: 1  Warnings: 0

MariaDB [l]> select * from products;
+------+----------------+
| name | caracteristics |
+------+----------------+
| val1 | asdfasdfasdf   |
| val2 | asdasDasd      |
| val3 | aesfawfa       |
+------+----------------+
3 rows in set (0.00 sec)

MariaDB [l]>

测试ADD PRIMARY KEY / INSERT IGNORE

这是添加主键和插入忽略之间的测试。并且您可以看到添加主键(90秒/ 120秒)在此示例中稍快一点

MariaDB [l]> CREATE TABLE `bigtable10m` (
    ->   `id` varchar(32) NOT NULL DEFAULT ''
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.02 sec)

MariaDB [l]>
MariaDB [l]> INSERT INTO `bigtable10m`
    -> select lpad(seq,8,'0') from seq_1_to_10000000;
Query OK, 10000000 rows affected (24.24 sec)
Records: 10000000  Duplicates: 0  Warnings: 0

MariaDB [l]>
MariaDB [l]> SELECT * FROM `bigtable10m` LIMIT 10;
+----------+
| id       |
+----------+
| 00000001 |
| 00000002 |
| 00000003 |
| 00000004 |
| 00000005 |
| 00000006 |
| 00000007 |
| 00000008 |
| 00000009 |
| 00000010 |
+----------+
10 rows in set (0.00 sec)

MariaDB [l]>
MariaDB [l]> CREATE TABLE `bigtable30m` (
    ->   `id` varchar(32) NOT NULL DEFAULT ''
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.02 sec)

MariaDB [l]>
MariaDB [l]> INSERT INTO `bigtable30m` SELECT * FROM `bigtable10m`;
Query OK, 10000000 rows affected (28.49 sec)
Records: 10000000  Duplicates: 0  Warnings: 0

MariaDB [l]> INSERT INTO `bigtable30m` SELECT * FROM `bigtable10m`;
Query OK, 10000000 rows affected (29.01 sec)
Records: 10000000  Duplicates: 0  Warnings: 0

MariaDB [l]> INSERT INTO `bigtable30m` SELECT * FROM `bigtable10m`;
Query OK, 10000000 rows affected (32.98 sec)
Records: 10000000  Duplicates: 0  Warnings: 0

MariaDB [l]>
MariaDB [l]> ALTER IGNORE TABLE `bigtable30m` ADD PRIMARY KEY(id);
Query OK, 30000000 rows affected (1 min 32.34 sec)
Records: 30000000  Duplicates: 20000000  Warnings: 0

MariaDB [l]>
MariaDB [l]> DROP TABLE `bigtable30m`;
Query OK, 0 rows affected (0.52 sec)

MariaDB [l]>
MariaDB [l]> CREATE TABLE `bigtable30m` (
    ->   `id` varchar(32) NOT NULL DEFAULT ''
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.03 sec)

MariaDB [l]>
MariaDB [l]> INSERT INTO `bigtable30m` SELECT * FROM `bigtable10m`;
Query OK, 10000000 rows affected (37.29 sec)
Records: 10000000  Duplicates: 0  Warnings: 0

MariaDB [l]> INSERT INTO `bigtable30m` SELECT * FROM `bigtable10m`;
Query OK, 10000000 rows affected (41.87 sec)
Records: 10000000  Duplicates: 0  Warnings: 0

MariaDB [l]> INSERT INTO `bigtable30m` SELECT * FROM `bigtable10m`;
Query OK, 10000000 rows affected (30.87 sec)
Records: 10000000  Duplicates: 0  Warnings: 0

MariaDB [l]>
MariaDB [l]> CREATE TABLE bigtable_unique (
    ->   `id` varchar(32) NOT NULL DEFAULT '',
    ->  PRIMARY KEY (id)
    -> );
Query OK, 0 rows affected (0.02 sec)

MariaDB [l]>
MariaDB [l]> INSERT IGNORE bigtable_unique SELECT * FROM `bigtable30m`;
Query OK, 10000000 rows affected, 65535 warnings (1 min 57.99 sec)
Records: 30000000  Duplicates: 20000000  Warnings: 20000000

MariaDB [l]>

答案 2 :(得分:0)

是的,修复性能问题是个好主意。当您遇到严重的性能问题时,这是正确的答案,足以让您对性能修复感到疑惑。

您可以通过改变table并使name成为primary key来实现这一目标,正如您已经意识到的那样。

您的查询不是必需的。您应该创建一个临时table,而不是insert您认为必要的值。我们假设该表的名称为mytemptable。然后:

insert into mytemptable(name, characteristics)
select name, characteristics
from products
where not exists (select 1
                  from mytemptable t
                  where products.name = t.name);

然后使用

products删除您的记录
delete from products;

然后alter products,确保nameprimary key,然后

insert into products(name, characteristics)
select name, characteristics
from mytemptable;

最后drop你的临时表。

关于您的查询:

由于您删除了记录,如果您有一个与给定max(name)值相关联的namename,则characteristics将等于您论坛中的所有其他characteristics,这是非常安全的假设..所以,如果你有一个name值与一个name匹配,你将删除1的所有实例,所以是的,你的查询会搞乱你的数据。