使用 MySQL 按空值进行分区
Posted
技术标签:
【中文标题】使用 MySQL 按空值进行分区【英文标题】:Partitions by null values with MySQL 【发布时间】:2015-04-01 12:55:11 【问题描述】:我有一张桌子:
CREATE TABLE `NewTable` (
`IBLOCK_ELEMENT_ID` int(11) NOT NULL ,
`PROPERTY_1836` int(11) NULL DEFAULT NULL ,
`DESCRIPTION_1836` varchar(255) CHARACTER SET cp1251 COLLATE cp1251_general_ci NULL DEFAULT NULL ,
`PROPERTY_1837` int(11) NULL DEFAULT 0 ,
`DESCRIPTION_1837` varchar(255) CHARACTER SET cp1251 COLLATE cp1251_general_ci NULL DEFAULT NULL ,
`PROPERTY_1838` decimal(18,4) NULL DEFAULT NULL ,
`DESCRIPTION_1838` varchar(255) CHARACTER SET cp1251 COLLATE cp1251_general_ci NULL DEFAULT NULL ,
`PROPERTY_3139` int(11) NULL DEFAULT 0 ,
`DESCRIPTION_3139` varchar(255) CHARACTER SET cp1251 COLLATE cp1251_general_ci NULL DEFAULT NULL ,
`PROPERTY_3173` decimal(18,4) NULL DEFAULT NULL ,
`DESCRIPTION_3173` varchar(255) CHARACTER SET cp1251 COLLATE cp1251_general_ci NULL DEFAULT NULL ,
PRIMARY KEY (`IBLOCK_ELEMENT_ID`),
INDEX `ix_perf_b_iblock_element_pr_1` (`PROPERTY_1837`) USING BTREE ,
INDEX `ix_perf_b_iblock_element_pr_2` (`PROPERTY_1836`) USING BTREE ,
INDEX `ix_perf_b_iblock_element_pr_3` (`PROPERTY_3139`) USING BTREE
)
ENGINE=InnoDB
DEFAULT CHARACTER SET=cp1251 COLLATE=cp1251_general_ci
ROW_FORMAT=COMPACT;
还有一个带有条件的查询:
WHERE PROPERTY_3139 IS NULL
我无法更改表或查询。但我知道,如果我将一个表拆分为 2 个分区 - 只选择可为空值的查询会运行得更快。
我可以使用什么样的技巧来做到这一点? NULL 和 NOT NULL 不是一个范围,我不能将它用作值列表。
【问题讨论】:
如果不能换表,还指望怎么加分区? 对于不准确之处,我深表歉意。我无法更改表格的结构。但分区不会影响查询的任何更改。 为什么这个问题是减号? 我没有否决这个问题。但是“我无法更改表或查询”的问题并没有留下很多改进的选择。 【参考方案1】:PARTITION
可能没用。
NULL
是 INDEX 中的一个单独值。将 NULL 视为在所有其他值之前存储在 INDEX 中。因此,出于优化目的,IS NULL
和 IS NOT NULL
可以被视为一个“范围”。
但是...如果超过 20%(10%-30%,取决于月相)的表在所需范围内,优化器将决定执行全表扫描更快而不是在 INDEX 和 Data 之间来回弹跳。
回到我的可能...
如果少数行有NULL,索引就可以了;分区不会有太大帮助。 如果中等数量的行具有 NULL,则 PARTITIONing 可以显着提供帮助。 如果大多数行都有 NULL,则全表扫描几乎与扫描一个 PARTITION 的所有内容一样好。注意:您不能对多个列进行 PARTITION。因此,如果您在PROPERTY_3139
上进行分区,则其余属性将不走运。
【讨论】:
非常感谢您的回答。您的“可能”让我认为重写生成该查询的代码更合理。因为此属性的 Null 值的行更多。 您的 WHERE 子句是否仅测试一列是否为 NULL?现在是性能问题吗?还是桌子会增长很多?有多少百分比的表有 NULL?如果值得进一步研究,请开始一个新问题,重点关注这些问题的答案。 96% 的行具有 NULL 值(总共 393940 行)。 CMS 生成的查询,将这个表与另一个表连接起来。所以,我认为重写php代码会非常有效。将其分成两个查询 - 第一个将选择所需表的 ID,第二个将获取详细信息。以上是关于使用 MySQL 按空值进行分区的主要内容,如果未能解决你的问题,请参考以下文章