Php 如何在mysql数据库中存储数据对?

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”参数)进行数据检索。该数据库将包含数百万对。插入和读取将非常频繁,删除或更新记录的

我必须存储大量的数据对。数据对的形式如下:

参数=值

与容器相关。它类似于INI文件。例如,我有一个具有以下值的容器:

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