Related
Currently we have table:
CREATE TABLE `T_TRANS` (
`CASE_ID` varchar(20) DEFAULT NULL,
`C_ID` varchar(20) DEFAULT NULL,
`C_ST_IND` smallint(6) DEFAULT NULL,
`D_DTTM` int(11) DEFAULT NULL,
`E_ID` varchar(10) DEFAULT NULL,
`E_LONG` decimal(11,7) DEFAULT NULL,
`E_LAT` decimal(9,7) DEFAULT NULL,
`EV_IND` smallint(6) DEFAULT NULL,
`H_B_IND` smallint(6) DEFAULT NULL,
`V_IND` varchar(15) DEFAULT NULL,
`I_IND` smallint(6) DEFAULT NULL,
`I_P_IND` smallint(6) DEFAULT NULL,
`I_S_IND` smallint(6) DEFAULT NULL,
`IS_D_IND` smallint(6) DEFAULT NULL,
`IS_R_IND` smallint(6) DEFAULT NULL,
`L_IND` smallint(6) DEFAULT NULL,
`D_LONG` decimal(11,7) DEFAULT NULL,
`D_LAT` decimal(9,7) DEFAULT NULL,
`L_P_C_DTTM` int(11) DEFAULT NULL,
`L_T_E_DTTM` int(11) DEFAULT NULL,
`M_IND` varchar(20) DEFAULT NULL,
`N_D_COUNTER` smallint(6) DEFAULT NULL,
`O_ID` smallint(6) NOT NULL,
`P_ID` varchar(50) DEFAULT NULL,
`R_E_IND` smallint(6) DEFAULT NULL,
`R_IND` smallint(6) DEFAULT NULL,
`S_C_DTTM` varchar(20) DEFAULT NULL,
`S_IND` smallint(6) DEFAULT NULL,
`T_T_RED` varchar(20) DEFAULT NULL,
`U_D` int(11) DEFAULT NULL,
`V_D` int(11) DEFAULT NULL,
`CRT_USR_NAM` varchar(45) DEFAULT NULL,
`CRT_DTTM` varchar(45) DEFAULT NULL,
`UPD_USR_NAM` varchar(45) DEFAULT NULL,
`UPD_DTTM` varchar(45) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
My where query will be on the following columns for a specific or combination of values
C_ST_IND values range from (0,1,2,3,4,5,6,7,8,9,10,11,12)
E_IND values range from (0,1,2,3,4,5,6,7)
R_IND Values range from (0,1)
R_E_IND Values range from (0,1)
L_IND Values range from (0,1)
IS_D_IND Values range from (0,1)
I_S_IND Values range from (0,1)
I_P_IND Values range from (0,1)
I_IND Values range from (0,1)
S_IND Values range from (0,1,2,3)
H_B_IND Values range from (0,1)
O_ID Values range from (1,2,3,4,5,6)
Also my date columns are in varchar with format - '2019-01-25 01:01:59'
CRT_DTTM and UPD_DTTM
On average - Daily Load will be
CRT_DTTM Count
2019-01-20 656601
2019-01-21 686018
2019-01-22 668486
2019-01-23 680922
2019-01-24 693700
This table has millions of records now and currently in production- without any partition and index.
It is taking lot of time - to run any query.
Now, i need to create partitions/Index. Tried partition on a existing table , it takes forerver to run.
What is the best partition methods for above listed columns (frequently used in where clause) and for date columns(CRT_DTTM and UPD_DTTM) for Year, Month, Week and Day Partition.
Also any indexes?
This table will hold Three Years of data. Right now we have 3 Months of data.
How do i move my current table to a new partitioned table. I am new to mysql, any information would help reduce production query run time and report generation.
PARTITIONs do not intrinsically provide any performance. Let's see the queries so we can judge whether you have one of the rare cases, such as purging 'old' data.
Suggest you shrink the data -- SMALLINT takes 2 bytes; TINYINT UNSIGNED takes 1 byte and can easily hold all those small values you mention. 7 decimal places for lat/lng gives you the precision of under 16mm or less than one inch. Do you need that much precision? Consider DECIMAL(8,6) for latitude and (9,6) for longitude; that will save 3 bytes for each pair. (Hmmm.. Why are there two pairs?)
"A long time to run 'any' query"? Let's see some of them and work on optimizing them. The usual problem is that you need to touch lots of rows. Shrinking the rows (as mentioned above) will help some. But the big improvement comes with not touching as many rows.
This smells like a Data Warehouse application? If so, perhaps building and maintaining Summary tables is the way to go. See http://mysql.rjweb.org/doc.php/summarytables . Show me some more info, and I will help you.
Do you intend to purge data after 3 years? If so, I recommend partitioning by month and have 38 partitions. Details here: http://mysql.rjweb.org/doc.php/partitionmaint . With that, the 680K-row nightly DELETE becomes a much quicker DROP PARTITION. (Meanwhile, there is probably no benefit to the performance of queries.)
My Index Cookbook: http://mysql.rjweb.org/doc.php/index_cookbook_mysql
I want to apply update to a table row through mysql prepared statement based on time difference between column installed and actual time DATEDIFF.
Here is my update and insert statement:
CREATE TABLE `installs` (
`idinstalls` int(11) NOT NULL AUTO_INCREMENT,
`key` varchar(45) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`DateTime` varchar(255) DEFAULT NULL,
`channelpref` varchar(255) DEFAULT NULL,
`contractorid` varchar(45) DEFAULT NULL,
`additiona` varchar(255) DEFAULT NULL,
`mail` varchar(255) DEFAULT NULL,
`installed` varchar(255) DEFAULT NULL,
`version` varchar(45) DEFAULT NULL,
`process` varchar(45) DEFAULT NULL,
PRIMARY KEY (`idinstalls`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=latin1;
INSERT INTO `installs` VALUES (1,'1478997547716','Test instalation 1','2016-12-05 10:47:21',NULL,NULL,'Test',NULL,'2016-11-13 01:39:07',NULL,''),(2,'1478997633546','Tomo','2017-01-24 16:05:10',NULL,NULL,'Test',NULL,'2016-11-13 01:40:33',NULL,''),(3,'1479003293243','Test instalation 2','2017-01-24 04:26:49',NULL,NULL,'Test',NULL,'2016-11-13 03:14:53',NULL,''),(4,'1479118582052','Beta','2016-11-21 19:40:10',NULL,NULL,'Test','','2016-11-14 11:16:22',NULL,''),(5,'1479124220728','Beta 2','2017-01-22 15:54:41',NULL,NULL,'Test','','2016-11-14 12:50:20',NULL,''),(14,'1480154887591','','2016-11-26 12:41:01',NULL,NULL,NULL,NULL,'2016-11-26 11:08:07',NULL,''),(17,'1483456759196','','2017-01-13 11:42:06',NULL,NULL,NULL,NULL,'2017-01-03 16:19:20',NULL,''),(18,'1484474379679','','2017-01-24 12:12:41',NULL,NULL,NULL,NULL,'2017-01-15 10:59:41',NULL,'')
The columns that are relevant to this question are: key,name,installed and process.
Query should update column process based on these requisites:
If column name has a input (it is not null nor empty field) column process should be assigned value '1'.
If column name does not have input, query should check difference between 2 dates, first one is date and time that is in column installed for that row and other is actual current date and time, if datetime difference is greater than 30 days it should update column process for that row to a value '0'.
This is my Fiddle
You should use the datatype timestamp for columns DateTime and installed. Then you may do the following.
update installs set process = '1' where name is not null and name != '';
update installs set process = '0' where (name is null or name = '') and datediff(now(), installed) > 30;
If I was asking the question, I'd formulate the data set this way, and construct my question accordingly...
CREATE TABLE `installs` (
`idinstalls` int(11) NOT NULL AUTO_INCREMENT,
`key` varchar(45) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`installed` varchar(255) DEFAULT NULL,
PRIMARY KEY (`idinstalls`)
);
INSERT INTO `installs` VALUES
( 1,'16','Test instalation 1','2016-11-13 01:39:07'),
( 2,'46','Tomo' ,'2016-11-13 01:40:33'),
( 3,'43','Test instalation 2','2016-11-13 03:14:53'),
( 4,'52','Beta' ,'2016-11-14 11:16:22'),
( 5,'28','Beta 2' ,'2016-11-14 12:50:20'),
(14,'91','' ,'2016-11-26 11:08:07'),
(17,'96','' ,'2017-01-03 16:19:20'),
(18,'79','' ,'2017-01-15 10:59:41');
I'm working on an old project where long time ago I decided to store opening hours as text in the database. Example:
CREATE TABLE `places` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`place_name` varchar(100) NOT NULL,
`monday` varchar(11) DEFAULT NULL,
`tuesday` varchar(11) DEFAULT NULL,
`wednesday` varchar(11) DEFAULT NULL,
`thursday` varchar(11) DEFAULT NULL,
`friday` varchar(11) DEFAULT NULL,
`saturday` varchar(11) DEFAULT NULL,
`sunday` varchar(11) DEFAULT NULL,
PRIMARY KEY (`id`)
);
Up until now it was fine because this data was used only for informative purposes. Values inside monday-to-sunday columns are being filtered so that they have to strictly match the pattern: HH:MM-HH:MM, for example "08:00-17:30", while the NULL value means that place is closed on particular day.
However, now there is requirement to filter places by their opening time. Something like "show places that are open now". I could, and I have already prepared, query that will use SUBSTR and STR_TO_DATE functions to split opening times, but I'm not sure if this isn't going to kill my database. I'm expecting circa 100'000 rows and the original table is a "little" more complicated :)... this one is just an example.
Working (yet) SQL:
SET #currentTime := '16:00:00';
SELECT *
FROM `places`
WHERE `monday` IS NOT NULL
AND STR_TO_DATE(SUBSTR(`monday`, 1, 5), '%H:%i') <= #currentTime
AND STR_TO_DATE(SUBSTR(`monday`, 7, 5), '%H:%i') >= #currentTime
What do you think about it? Is there a nicer way to do that using existing DB structure or should I forget about such half measures and change the structure immediately?
I am trying to select current program (which is happening now) from this table. Please help Thanks.
CREATE TABLE `programs` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`p_day` varchar(20) NOT NULL,
`program` varchar(255) NOT NULL,
`p_start` time NOT NULL DEFAULT '00:00:00',
`p_end` time NOT NULL DEFAULT '00:00:00',
PRIMARY KEY (`id`)
)
SELECT program FROM programs
WHERE CURDATE() = p_day
AND CURTIME() BETWEEN p_start AND p_end;
I'm making an assumption that your p_day is a valid date string, e.g. '2011-08-15' but it's not clear from your question. Why didn't you use a DATE datatype for the p_day?
I have a table in MySQL that have a few columns that have default values specified, but when I try to insert a row, (not specifying values for those default columns), it throws an error saying I cannot insert NULL values.
Here is the table example;
CREATE TABLE `users` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`UniqueName` varchar(120) NOT NULL,
`Password` varchar(1000) NOT NULL,
`PublicFlag` tinyint(1) NOT NULL,
`NoTimesLoggedIn` int(10) unsigned NOT NULL DEFAULT '0',
`DateTimeLastLogin` timestamp NOT NULL DEFAULT '1971-01-01 00:00:00',
`UserStatusTypeId` int(10) unsigned NOT NULL,
`Private` tinyint(1) NOT NULL DEFAULT '0',
`SiteName` varchar(255) NOT NULL,
`CountryId` int(10) NOT NULL DEFAULT '0',
`TimeZoneId` varchar(255) NOT NULL DEFAULT 'UTC',
`CultureInfoId` int(10) unsigned NOT NULL DEFAULT '0',
`DateCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UserCreated` int(10) unsigned NOT NULL,
`LastUpdatedBy` int(10) unsigned NOT NULL,
`DateLastUpdated` datetime DEFAULT NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `UniqueName_UNIQUE` (`UniqueName`),
KEY `Index 3` (`SiteName`)
)
It complains about TimeZoneId, and when I populate TimeZoneId, it complains about CultureInforId.
I am using MySQL Version: 5.1.43-community
Here is the insert query I am trying to insert, grabbed from NHibernate Profiler:
INSERT INTO Users
(UniqueName,
Password,
PublicFlag,
NoTimesLoggedIn,
DateTimeLastLogin,
SiteName,
TimeZoneId,
DateCreated,
DateLastUpdated,
Private,
CountryId,
CultureInfoId,
UserCreated,
LastUpdatedBy,
UserStatusTypeId)
VALUES ('zma#zm.com','u1uhbQviLp89P9b3EnuN/Prvo3A4KVSiUa0=',1,
0,'1/01/1971 12:00:00 AM','V9O1T80Q6D',NULL,'2/08/2010 2:13:44 AM',
'2/08/2010 2:13:44 AM',0, NULL, NULL, 4, 4,31)
Use the DEFAULT keyword instead:
INSERT INTO users (TimeZoneId) VALUES (DEFAULT);
Do not insert NULL values. I'm assuming you were trying this syntax:
INSERT INTO users VALUES (null, 'Jones', 'yarg', 1, null, null, null);
Instead, use this syntax:
INSERT INTO users SET UniqueName='Jones', Password='yarg';
For more info, see the MySQL docs on INSERT.
You have "NOT NULL" set on fields that you are trying to INSERT NULL on.
eg.
CountryId,
CultureInfoId,
TimeZoneId
execute the following:
ALTER TABLE `users` MODIFY `CountryId` int(10) DEFAULT '0' NULL;
ALTER TABLE `users` MODIFY `CultureInfoId` int(10) unsigned DEFAULT '0' NULL;
ALTER TABLE `users` MODIFY `TimeZoneId` varchar(255) DEFAULT 'UTC' NULL;
EDIT: Didn't realize he wanted the default value instead of NULL on "null" insert. Basically as already has been suggested use the DEFAULT keyword in place of NULL on the values.
OR leave the NULL fields and values out altogether and mysql will use the defined defaults eg.
INSERT INTO Users
(UniqueName,
Password,
PublicFlag,
NoTimesLoggedIn,
DateTimeLastLogin,
SiteName,
DateCreated,
DateLastUpdated,
Private,
UserCreated,
LastUpdatedBy,
UserStatusTypeId)
VALUES ('zma#zm.com','u1uhbQviLp89P9b3EnuN/Prvo3A4KVSiUa0=',1,
0,'1/01/1971 12:00:00 AM','V9O1T80Q6D','2/08/2010 2:13:44 AM',
'2/08/2010 2:13:44 AM',0, 4, 4,31)
The documentation says that from version 5.6 you need to access fields by default.
I've read this post about this trouble
I've fixed it this way:
mysql> show global variables like 'explicit_defaults_for_timestamp';
And if your field has ON value change to OFF
mysql> set global explicit_defaults_for_timestamp=0;
That's all.
As an alternative to using the DEFAULT keyword you can also just not specify values for the fields which you want to have default values. For instance if you just removed TimeZoneId, CountryId and CultureInfoId from your query entirely those columns will receive the default values automatically:
INSERT INTO Users
(UniqueName,
Password,
PublicFlag,
NoTimesLoggedIn,
DateTimeLastLogin,
SiteName,
DateCreated,
DateLastUpdated,
Private,
UserCreated,
LastUpdatedBy,
UserStatusTypeId)
VALUES
('zma#zm.com','u1uhbQviLp89P9b3EnuN/Prvo3A4KVSiUa0=',1,0,
'1/01/1971 12:00:00 AM','V9O1T80Q6D','2/08/2010 2:13:44 AM',
'2/08/2010 2:13:44 AM',0,4,4,31)
I'm not sure how that would work in the context of NHibernate however as that part of the question wasn't quite as well explained.
TimeZoneIdvarchar(255) NOT NULL DEFAULT 'UTC',
CultureInfoId` int(10) unsigned NOT NULL DEFAULT '0',
For this fields you have set constraints as "Not Null" and hence values inserted can't be null and hence either alter the table structure or just not specify values for the fields which you want to have default values.