Создайте новый индексированный столбец, содержащий только столбец даты и времени VS. index индекса года и месяца напрямую - PullRequest
2 голосов
/ 04 июня 2019

Проблема в том, что мне нужно вести большую таблицу с сотнями миллионов строк, и мне нужно запрашивать базу данных по годам и месяцам. Будет ли он лучше работать, если я создам новый столбец с указанием только года и месяца, например 1906 (unsigned small int), вместо того, чтобы создавать базу индексов непосредственно для столбца timestamp / datetime (точность секунд, например "2019-06-03 11 : 22" )

?

И уменьшит ли он размер индекса?

Ответы [ 3 ]

1 голос
/ 04 июня 2019

Я сгенерировал 14 миллионов строк данных и протестировал с помощью текущей процедуры, я не знаю, как объяснить результат, однако это результат.

Платформа

OS: Ubuntu 18.04 (virtual machine)
MySQL: 5.7

ТестРезультат

время, затраченное на выполнение запроса

index           data type          sample data    max     min      avg
int3          | int(3)   |            20170902| 0.248|  0.169|  0.1946
int10         | int(10)  |              201709| 0.248|  0.183|  0.2016
smallint      | smallint |                1709| 0.306|  0.182|  0.2114
int4          | int(4)   |              201709| 0.325|  0.175|  0.2138
date          | date     |          2017-09-02| 0.397|  0.242|  0.2772
datetime_date | datetime | 2017-09-02 00:00:00| 0.422|  0.278|  0.3108
datetime      | datetime | 2017-09-02 05:00:01| 0.437|  0.279|  0.3142
timestamp     | timestamp| 2017-09-02 05:00:01| 0.96 |   0.79|  0.8306
timestamp_date| timestamp| 2017-09-02 00:00:00| 0.978|  0.792|  0.8392

Структура таблицы

DROP TABLE `datetime_index_test`;
CREATE TABLE `datetime_index_test` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`datetime` datetime NULL,
`datetime_date` datetime NULL,
`timestamp` timestamp NULL,
`timestamp_date` timestamp NULL,
`smallint` smallint unsigned NULL,
`int10` int(10) unsigned NULL,
`int4` int(4) unsigned NULL,
`int3` int(3) unsigned NULL,
`date` date NULL,
PRIMARY KEY (`id`),
KEY `idx_datetime` (`datetime`),
KEY `idx_datetime_date` (`datetime_date`),
KEY `idx_timestamp` (`timestamp`),
KEY `idx_timestamp_date` (`timestamp_date`),
KEY `idx_smallint` (`smallint`),
KEY `idx_int10` (`int10`),
KEY `idx_int4` (`int4`),
KEY `idx_int3` (`int3`),
KEY `idx_date` (`date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Пример данных

             datetime            timestamp  smallint   int10    int4      int3        date  datetime_date  timestamp_date
  2017-09-01 00:17:50| 2017-09-01 00:17:50|     1709| 201709| 201709| 20170901| 2017-09-01|    2017-09-01|     2017-09-01
  2017-09-01 01:03:53| 2017-09-01 01:03:53|     1709| 201709| 201709| 20170901| 2017-09-01|    2017-09-01|     2017-09-01
  2017-09-01 02:29:56| 2017-09-01 02:29:56|     1709| 201709| 201709| 20170901| 2017-09-01|    2017-09-01|     2017-09-01
  2017-09-01 03:15:05| 2017-09-01 03:15:05|     1709| 201709| 201709| 20170901| 2017-09-01|    2017-09-01|     2017-09-01
  2017-09-01 04:22:50| 2017-09-01 04:22:50|     1709| 201709| 201709| 20170901| 2017-09-01|    2017-09-01|     2017-09-01
  2017-09-01 05:07:05| 2017-09-01 05:07:05|     1709| 201709| 201709| 20170901| 2017-09-01|    2017-09-01|     2017-09-01
  2017-09-01 06:41:12| 2017-09-01 06:41:12|     1709| 201709| 201709| 20170901| 2017-09-01|    2017-09-01|     2017-09-01

Команда SQL

Index: int3
SQL: SELECT COUNT(*) FROM `datetime_index_test` WHERE `int3`>=20180601 AND `int3`<20180701;

Index: int10
SQL: select count(*) from `datetime_index_test` where `int10`>=201806 and `int10`<201807;

Index: smallint
SQL: SELECT COUNT(*) FROM `datetime_index_test` WHERE `smallint`>=1806 AND `smallint`<1807;

Index: int4
SQL: SELECT COUNT(*) FROM `datetime_index_test` WHERE `int4`>=201806 AND `int4`<201807;

Index: date
SQL: SELECT COUNT(*) FROM `datetime_index_test` WHERE `date`>="2018-06-01 00:00" AND `date`<"2018-07-01 00:00";

Index: datetime_date
SQL: SELECT COUNT(*) FROM `datetime_index_test` WHERE `datetime_date`>="2018-06-01 00:00" AND `datetime_date`<"2018-07-01 00:00";

Index: datetime
SQL: SELECT COUNT(*) FROM `datetime_index_test` WHERE `datetime`>="2018-06-01 00:00" AND `datetime`<"2018-07-01 00:00";

Index: timestamp
SQL: SELECT COUNT(*) FROM `datetime_index_test` WHERE `timestamp`>="2018-06-01 00:00" AND `timestamp`<"2018-07-01 00:00";

Index: timestamp_date
SQL: SELECT COUNT(*) FROM `datetime_index_test` WHERE `timestamp_date`>="2018-06-01 00:00" AND `timestamp_date`<"2018-07-01 00:00";

Python-код для генерации примера данных

import pandas as pd
import numpy as np
df = pd.date_range(start="2017-09-01 00:00", end="2019-05-01 00:00", freq='h').rename('datetime').to_frame().reset_index(drop=True)
df = pd.concat([df]*1000, axis=0)
arr = np.random.randint(low=0, high=3600, size=(len(df))) 
arr = arr*np.timedelta64(1, 's')
df['datetime'] = df['datetime']+ arr
df = df.sort_values(['datetime'])
df = df.reset_index(drop=True)
df['timestamp'] = df['datetime']
df['smallint'] = df['timestamp'].dt.year-2000
df['smallint'] = df['smallint']*100
df['smallint'] = df['timestamp'].dt.month + df['smallint']
df['int10'] = df['smallint']+ 200000
df['int4'] = df['int10']
df['int3'] = df['int4']*100 + df['datetime'].dt.day
df['date'] = df['timestamp'].dt.date
df['datetime_date'] = df['date']
df['timestamp_date'] = df['date']
0 голосов
/ 04 июня 2019

... хранилище данных, данные которого обновляются каждую ночь ... И большая часть данных используется для статистики по дате или по неделям / месяцам

В этом случае вы задаете не тот вопрос. «Настоящий» вопрос заключается в том, как эффективно получать ежедневные / еженедельные / ежемесячные статистические данные из Data Wherehouse. Ответ заключается в создании и ведении сводных таблиц.

Поскольку вы каждую ночь загружаете новые данные за день (если я правильно интерпретирую ваше утверждение), то это отличное время для суммирования данных за один день и заполнения строк в сводной таблице. Такая таблица может иметь только одну десятую от числа строк и может быть проиндексирована в несколько строк. Затем отображение статистики может суммировать ежедневные промежуточные итоги, чтобы получить недельный / месячный / произвольный диапазон дат. Такая таблица будет иметь столбец DATE. Согласно исследованию Чена, это не самое лучшее, но с ним проще работать, чем с некоторой формой int. Что еще более важно, это, вероятно, крошечный процент от общего времени. Сводная таблица будет намного меньше, поэтому один или два байта (размером с столбец даты) не будут иметь значения по сравнению с общим потребляемым дисковым пространством.

Дополнительные обсуждения Сводные таблицы

0 голосов
/ 04 июня 2019

Да и Да.Меньшее количество данных в столбце и индексе будет быстрее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...