Php 如何在mysql数据库中存储数据对?
我必须存储大量的数据对。数据对的形式如下: 参数=值 与容器相关。它类似于INI文件。例如,我有一个具有以下值的容器:Php 如何在mysql数据库中存储数据对?,php,mysql,database,entity-attribute-value,Php,Mysql,Database,Entity Attribute Value,我必须存储大量的数据对。数据对的形式如下: 参数=值 与容器相关。它类似于INI文件。例如,我有一个具有以下值的容器: p1 = 32 p2 = "hello world" p3 = -54 还有一个: p1 = 32 p2 = 36 p5 = 42 p6 = "bye" 每个容器的参数数量未定义。值是任意长度的数字或字符串(数字可以转换为字符串)。通过参数名称(“所有p1值”)或值(“值为“bye”的“p6”参数)进行数据检索。该数据库将包含数百万对。插入和读取将非常频繁,删除或更新记录的
p1 = 32
p2 = "hello world"
p3 = -54
还有一个:
p1 = 32
p2 = 36
p5 = 42
p6 = "bye"
每个容器的参数数量未定义。值是任意长度的数字或字符串(数字可以转换为字符串)。通过参数名称(“所有p1值”)或值(“值为“bye”的“p6”参数)进行数据检索。该数据库将包含数百万对。插入和读取将非常频繁,删除或更新记录的情况很少
我的第一次尝试是做两张桌子。第一个是这样的:
CREATE TABLE IF NOT EXISTS `container` (
`id` int(11) NOT NULL AUTO_INCREMENT,
OTHER CONTAINER INFO
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
container name value
1 p1 32
1 p2 hello world
1 p3 -54
其中,id
将在另一个包含对的表中使用:
CREATE TABLE IF NOT EXISTS `data` (
`container` int(11) NOT NULL,
`name` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`value` text COLLATE utf8_unicode_ci NOT NULL,
KEY `container` (`container`),
KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
添加数据:
INSERT INTO `container` (`id`) VALUES ('1'), ('2');
INSERT INTO `data` (`container`, `name`, `value`) VALUES
('1', 'p1', '32'),
('1', 'p2', 'hello world'),
('1', 'p3', '-54'),
('2', 'p1', '32'),
('2', 'p2', '36'),
('2', 'p5', '42'),
('2', 'p6', 'bye');
它可以工作,但不是很“实用”和快速。例如,如果我需要从具有p1=32
的每个容器中查找所有参数,我必须进行两个SQL查询,首先:
SELECT id FROM `container` WHERE id IN (
SELECT container
FROM DATA WHERE name = 'p1'
AND value = '32')
然后为每个容器id
获取所有数据:
SELECT * FROM `data` WHERE container = '$id'
然后通过PHP进行后处理,因为它返回如下表:
CREATE TABLE IF NOT EXISTS `container` (
`id` int(11) NOT NULL AUTO_INCREMENT,
OTHER CONTAINER INFO
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
container name value
1 p1 32
1 p2 hello world
1 p3 -54
(后处理只是对array_*函数的几次调用,但会降低处理速度)
我一直在使用一个包含50000个数据对的数据库进行测试,使用此过程列出所有记录需要5秒钟以上。问题是:如何存储此类数据?或者如何改进我的实现的性能
注意:问题不是第一个SQL查询(0'003秒)或第二个SQL查询(每个查询0'002秒)。问题是对第一个SQL语句的每个结果进行SQL查询
注2:目标是拥有一个包含每个结果的PHP数组,并为每个结果创建一个带有pairs键值的关联数组。打印的结果\r
:
Array
(
[1] => Array
(
[p1] => 32
[p2] => hello world
[p3] => -54
)
[2] => Array
(
[p1] => 32
[p2] => 36
[p5] => 42
[p6] => bye
)
)
当然,我在这里展示的数据结构是我的第一次尝试,我正在研究,这不是一个产品,所以我可以更改,一点问题也没有。你不需要两个单独的查询,连接在那里很好;子选择也不是必需的。您的两个查询如下:
SELECT id FROM `container` c
JOIN data d ON c.id = d.container
d.name = 'p1'
AND d.value = '32';
好的,我看到你的便条了,你想要所有的数据都在同一行吗?我不会使用此查询,但这些是您想要的结果吗
SELECT id, GROUP_CONCAT(CONCAT_WS("=", d.name, d.value)) results FROM `container` c
JOIN data d ON c.id = d.container
HAVING LOCATE("p1=32", results) > 0;
试试这个:
SELECT
container.id
FROM
`container`
LEFT JOIN `DATA`
ON container.ID = DATA.container
WHERE DATA.name = 'p1'
AND DATA.value = '32'
如果希望每个容器的所有结果都在一行上,可能需要使用透视表。但是,考虑到您可能会获得数量可变的data.name值,您不能仅在一个简单的查询中执行此操作。您需要编写一个过程来动态生成sql 此链接应该可以帮助您: 生成的SQL应该类似(未测试) 给出如下结果:
|id |p1 |p2 |p3 |p4 |p5 |p6 |
-------------------------------------------------------
|1 |32 |hello world |-54 | | | |
|2 |32 |36 | | |42 |bye |
只需将数据表本身连接起来,您就可以在一次选择中获得所需的一切:
select d2.container, d2.name, d2.value
from data d1
join data d2 using(container)
where d1.name = 'p1'
and d1.value = '32';
结果:
| container | name | value |
|-----------|------|-------------|
| 1 | p1 | 32 |
| 1 | p2 | hello world |
| 1 | p3 | -54 |
| 2 | p1 | 32 |
| 2 | p2 | 36 |
| 2 | p5 | 42 |
| 2 | p6 | bye |
[
1=>["p1"=>"32","p2"=>"hello world","p3"=>"-54"],
2=>["p1"=>"32","p2"=>"36","p5"=>"42","p6"=>"bye"]
]
您还可以在sql中创建有效的php数组字符串:
select concat('[', GROUP_CONCAT(d.row), '\n]')
from (
select concat('\n\t', d2.container, '=>[', GROUP_CONCAT(concat('"', d2.name, '"', '=>', '"', d2.value, '"')), ']') as row
from data d1
join data d2 using(container)
where d1.name = 'p1'
and d1.value = '32'
group by d2.container
) d;
结果:
| container | name | value |
|-----------|------|-------------|
| 1 | p1 | 32 |
| 1 | p2 | hello world |
| 1 | p3 | -54 |
| 2 | p1 | 32 |
| 2 | p2 | 36 |
| 2 | p5 | 42 |
| 2 | p6 | bye |
[
1=>["p1"=>"32","p2"=>"hello world","p3"=>"-54"],
2=>["p1"=>"32","p2"=>"36","p5"=>"42","p6"=>"bye"]
]
但是为什么会有人想这样做呢?;-)
更新-还可以尝试以下键:
ALTER TABLE `data` ADD UNIQUE INDEX `container_name` (`container`, `name`);
ALTER TABLE `data` ADD INDEX `name_value` (`name`, `value`(20));
您可能还需要在web上搜索抱歉,但它不起作用。它只返回容器ID,与我的第一个SQL相同query@Ivan我以为这就是你想要的。它返回与上一个查询相同的结果,但速度要快得多。这是一个更优化的版本,您的选择相同。你还需要什么数据?这不是问题所在。列表仍然需要5秒钟。请看我的笔记。它返回一个字符串(“p1=32,p2=hello world,p3=-54,p1=32,p2=36,p5=42,p6=bye”),但我不能使用它,因为它没有容器ID。我还没有为此测试性能。无论如何,这是一个很好的研究点,我还没有探索过。谢谢。它选择了两列,第一列有容器id,第二列有所有的字符串。这很有趣,但它有一个问题:我不知道存储了哪些对,可能是p9,也可能不是。是的,我知道,这就是为什么你需要先写一个存储过程来构建查询(参见链接)。基本上,它应该像我的示例中那样构造一个查询,但是对于data.name(您感兴趣的)的所有不同值,都应该使用一个group_concat