You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

install.sql 25 KiB

4 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  1. 
  2. -- This file is part of Hangfire.
  3. -- Copyright © 2013-2014 Sergey Odinokov.
  4. --
  5. -- Hangfire is free software: you can redistribute it and/or modify
  6. -- it under the terms of the GNU Lesser General Public License as
  7. -- published by the Free Software Foundation, either version 3
  8. -- of the License, or any later version.
  9. --
  10. -- Hangfire is distributed in the hope that it will be useful,
  11. -- but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. -- GNU Lesser General Public License for more details.
  14. --
  15. -- You should have received a copy of the GNU Lesser General Public
  16. -- License along with Hangfire. If not, see <http://www.gnu.org/licenses/>.
  17. SET NOCOUNT ON
  18. SET XACT_ABORT ON
  19. DECLARE @TARGET_SCHEMA_VERSION INT;
  20. DECLARE @DISABLE_HEAVY_MIGRATIONS BIT;
  21. SET @TARGET_SCHEMA_VERSION = 7;
  22. --SET @DISABLE_HEAVY_MIGRATIONS = 1;
  23. PRINT 'Installing Hangfire SQL objects...';
  24. BEGIN TRANSACTION;
  25. -- Acquire exclusive lock to prevent deadlocks caused by schema creation / version update
  26. DECLARE @SchemaLockResult INT;
  27. EXEC @SchemaLockResult = sp_getapplock @Resource = 'HangFire:SchemaLock', @LockMode = 'Exclusive'
  28. -- Create the database schema if it doesn't exists
  29. IF NOT EXISTS (SELECT [schema_id] FROM [sys].[schemas] WHERE [name] = 'HangFire')
  30. BEGIN
  31. EXEC (N'CREATE SCHEMA [HangFire]');
  32. PRINT 'Created database schema [HangFire]';
  33. END
  34. ELSE
  35. PRINT 'Database schema [HangFire] already exists';
  36. DECLARE @SCHEMA_ID int;
  37. SELECT @SCHEMA_ID = [schema_id] FROM [sys].[schemas] WHERE [name] = 'HangFire';
  38. -- Create the [HangFire].Schema table if not exists
  39. IF NOT EXISTS(SELECT [object_id] FROM [sys].[tables]
  40. WHERE [name] = 'Schema' AND [schema_id] = @SCHEMA_ID)
  41. BEGIN
  42. CREATE TABLE [HangFire].[Schema](
  43. [Version] [int] NOT NULL,
  44. CONSTRAINT [PK_HangFire_Schema] PRIMARY KEY CLUSTERED ([Version] ASC)
  45. );
  46. PRINT 'Created table [HangFire].[Schema]';
  47. END
  48. ELSE
  49. PRINT 'Table [HangFire].[Schema] already exists';
  50. DECLARE @CURRENT_SCHEMA_VERSION int;
  51. SELECT @CURRENT_SCHEMA_VERSION = [Version] FROM [HangFire].[Schema];
  52. PRINT 'Current Hangfire schema version: ' + CASE WHEN @CURRENT_SCHEMA_VERSION IS NULL THEN 'none' ELSE CONVERT(nvarchar, @CURRENT_SCHEMA_VERSION) END;
  53. IF @CURRENT_SCHEMA_VERSION IS NOT NULL AND @CURRENT_SCHEMA_VERSION > @TARGET_SCHEMA_VERSION
  54. BEGIN
  55. ROLLBACK TRANSACTION;
  56. PRINT 'Hangfire current database schema version ' + CAST(@CURRENT_SCHEMA_VERSION AS NVARCHAR) +
  57. ' is newer than the configured SqlServerStorage schema version ' + CAST(@TARGET_SCHEMA_VERSION AS NVARCHAR) +
  58. '. Will not apply any migrations.';
  59. RETURN;
  60. END
  61. -- Install [HangFire] schema objects
  62. IF @CURRENT_SCHEMA_VERSION IS NULL
  63. BEGIN
  64. IF @DISABLE_HEAVY_MIGRATIONS = 1
  65. BEGIN
  66. SET @DISABLE_HEAVY_MIGRATIONS = 0;
  67. PRINT 'Enabling HEAVY_MIGRATIONS, because we are installing objects from scratch';
  68. END
  69. PRINT 'Installing schema version 1';
  70. -- Create job tables
  71. CREATE TABLE [HangFire].[Job] (
  72. [Id] [int] IDENTITY(1,1) NOT NULL,
  73. [StateId] [int] NULL,
  74. [StateName] [nvarchar](20) NULL, -- To speed-up queries.
  75. [InvocationData] [nvarchar](max) NOT NULL,
  76. [Arguments] [nvarchar](max) NOT NULL,
  77. [CreatedAt] [datetime] NOT NULL,
  78. [ExpireAt] [datetime] NULL,
  79. CONSTRAINT [PK_HangFire_Job] PRIMARY KEY CLUSTERED ([Id] ASC)
  80. );
  81. PRINT 'Created table [HangFire].[Job]';
  82. CREATE NONCLUSTERED INDEX [IX_HangFire_Job_StateName] ON [HangFire].[Job] ([StateName] ASC);
  83. PRINT 'Created index [IX_HangFire_Job_StateName]';
  84. -- Job history table
  85. CREATE TABLE [HangFire].[State] (
  86. [Id] [int] IDENTITY(1,1) NOT NULL,
  87. [JobId] [int] NOT NULL,
  88. [Name] [nvarchar](20) NOT NULL,
  89. [Reason] [nvarchar](100) NULL,
  90. [CreatedAt] [datetime] NOT NULL,
  91. [Data] [nvarchar](max) NULL,
  92. CONSTRAINT [PK_HangFire_State] PRIMARY KEY CLUSTERED ([Id] ASC)
  93. );
  94. PRINT 'Created table [HangFire].[State]';
  95. ALTER TABLE [HangFire].[State] ADD CONSTRAINT [FK_HangFire_State_Job] FOREIGN KEY([JobId])
  96. REFERENCES [HangFire].[Job] ([Id])
  97. ON UPDATE CASCADE
  98. ON DELETE CASCADE;
  99. PRINT 'Created constraint [FK_HangFire_State_Job]';
  100. CREATE NONCLUSTERED INDEX [IX_HangFire_State_JobId] ON [HangFire].[State] ([JobId] ASC);
  101. PRINT 'Created index [IX_HangFire_State_JobId]';
  102. -- Job parameters table
  103. CREATE TABLE [HangFire].[JobParameter](
  104. [Id] [int] IDENTITY(1,1) NOT NULL,
  105. [JobId] [int] NOT NULL,
  106. [Name] [nvarchar](40) NOT NULL,
  107. [Value] [nvarchar](max) NULL,
  108. CONSTRAINT [PK_HangFire_JobParameter] PRIMARY KEY CLUSTERED ([Id] ASC)
  109. );
  110. PRINT 'Created table [HangFire].[JobParameter]';
  111. ALTER TABLE [HangFire].[JobParameter] ADD CONSTRAINT [FK_HangFire_JobParameter_Job] FOREIGN KEY([JobId])
  112. REFERENCES [HangFire].[Job] ([Id])
  113. ON UPDATE CASCADE
  114. ON DELETE CASCADE;
  115. PRINT 'Created constraint [FK_HangFire_JobParameter_Job]';
  116. CREATE NONCLUSTERED INDEX [IX_HangFire_JobParameter_JobIdAndName] ON [HangFire].[JobParameter] (
  117. [JobId] ASC,
  118. [Name] ASC
  119. );
  120. PRINT 'Created index [IX_HangFire_JobParameter_JobIdAndName]';
  121. -- Job queue table
  122. CREATE TABLE [HangFire].[JobQueue](
  123. [Id] [int] IDENTITY(1,1) NOT NULL,
  124. [JobId] [int] NOT NULL,
  125. [Queue] [nvarchar](20) NOT NULL,
  126. [FetchedAt] [datetime] NULL,
  127. CONSTRAINT [PK_HangFire_JobQueue] PRIMARY KEY CLUSTERED ([Id] ASC)
  128. );
  129. PRINT 'Created table [HangFire].[JobQueue]';
  130. CREATE NONCLUSTERED INDEX [IX_HangFire_JobQueue_JobIdAndQueue] ON [HangFire].[JobQueue] (
  131. [JobId] ASC,
  132. [Queue] ASC
  133. );
  134. PRINT 'Created index [IX_HangFire_JobQueue_JobIdAndQueue]';
  135. CREATE NONCLUSTERED INDEX [IX_HangFire_JobQueue_QueueAndFetchedAt] ON [HangFire].[JobQueue] (
  136. [Queue] ASC,
  137. [FetchedAt] ASC
  138. );
  139. PRINT 'Created index [IX_HangFire_JobQueue_QueueAndFetchedAt]';
  140. -- Servers table
  141. CREATE TABLE [HangFire].[Server](
  142. [Id] [nvarchar](50) NOT NULL,
  143. [Data] [nvarchar](max) NULL,
  144. [LastHeartbeat] [datetime] NULL,
  145. CONSTRAINT [PK_HangFire_Server] PRIMARY KEY CLUSTERED ([Id] ASC)
  146. );
  147. PRINT 'Created table [HangFire].[Server]';
  148. -- Extension tables
  149. CREATE TABLE [HangFire].[Hash](
  150. [Id] [int] IDENTITY(1,1) NOT NULL,
  151. [Key] [nvarchar](100) NOT NULL,
  152. [Name] [nvarchar](40) NOT NULL,
  153. [StringValue] [nvarchar](max) NULL,
  154. [IntValue] [int] NULL,
  155. [ExpireAt] [datetime] NULL,
  156. CONSTRAINT [PK_HangFire_Hash] PRIMARY KEY CLUSTERED ([Id] ASC)
  157. );
  158. PRINT 'Created table [HangFire].[Hash]';
  159. CREATE UNIQUE NONCLUSTERED INDEX [UX_HangFire_Hash_KeyAndName] ON [HangFire].[Hash] (
  160. [Key] ASC,
  161. [Name] ASC
  162. );
  163. PRINT 'Created index [UX_HangFire_Hash_KeyAndName]';
  164. CREATE TABLE [HangFire].[List](
  165. [Id] [int] IDENTITY(1,1) NOT NULL,
  166. [Key] [nvarchar](100) NOT NULL,
  167. [Value] [nvarchar](max) NULL,
  168. [ExpireAt] [datetime] NULL,
  169. CONSTRAINT [PK_HangFire_List] PRIMARY KEY CLUSTERED ([Id] ASC)
  170. );
  171. PRINT 'Created table [HangFire].[List]';
  172. CREATE TABLE [HangFire].[Set](
  173. [Id] [int] IDENTITY(1,1) NOT NULL,
  174. [Key] [nvarchar](100) NOT NULL,
  175. [Score] [float] NOT NULL,
  176. [Value] [nvarchar](256) NOT NULL,
  177. [ExpireAt] [datetime] NULL,
  178. CONSTRAINT [PK_HangFire_Set] PRIMARY KEY CLUSTERED ([Id] ASC)
  179. );
  180. PRINT 'Created table [HangFire].[Set]';
  181. CREATE UNIQUE NONCLUSTERED INDEX [UX_HangFire_Set_KeyAndValue] ON [HangFire].[Set] (
  182. [Key] ASC,
  183. [Value] ASC
  184. );
  185. PRINT 'Created index [UX_HangFire_Set_KeyAndValue]';
  186. CREATE TABLE [HangFire].[Value](
  187. [Id] [int] IDENTITY(1,1) NOT NULL,
  188. [Key] [nvarchar](100) NOT NULL,
  189. [StringValue] [nvarchar](max) NULL,
  190. [IntValue] [int] NULL,
  191. [ExpireAt] [datetime] NULL,
  192. CONSTRAINT [PK_HangFire_Value] PRIMARY KEY CLUSTERED (
  193. [Id] ASC
  194. )
  195. );
  196. PRINT 'Created table [HangFire].[Value]';
  197. CREATE UNIQUE NONCLUSTERED INDEX [UX_HangFire_Value_Key] ON [HangFire].[Value] (
  198. [Key] ASC
  199. );
  200. PRINT 'Created index [UX_HangFire_Value_Key]';
  201. CREATE TABLE [HangFire].[Counter](
  202. [Id] [int] IDENTITY(1,1) NOT NULL,
  203. [Key] [nvarchar](100) NOT NULL,
  204. [Value] [tinyint] NOT NULL,
  205. [ExpireAt] [datetime] NULL,
  206. CONSTRAINT [PK_HangFire_Counter] PRIMARY KEY CLUSTERED ([Id] ASC)
  207. );
  208. PRINT 'Created table [HangFire].[Counter]';
  209. CREATE NONCLUSTERED INDEX [IX_HangFire_Counter_Key] ON [HangFire].[Counter] ([Key] ASC)
  210. INCLUDE ([Value]);
  211. PRINT 'Created index [IX_HangFire_Counter_Key]';
  212. SET @CURRENT_SCHEMA_VERSION = 1;
  213. END
  214. IF @CURRENT_SCHEMA_VERSION = 1
  215. BEGIN
  216. PRINT 'Installing schema version 2';
  217. -- https://github.com/odinserj/HangFire/issues/83
  218. DROP INDEX [IX_HangFire_Counter_Key] ON [HangFire].[Counter];
  219. ALTER TABLE [HangFire].[Counter] ALTER COLUMN [Value] SMALLINT NOT NULL;
  220. CREATE NONCLUSTERED INDEX [IX_HangFire_Counter_Key] ON [HangFire].[Counter] ([Key] ASC)
  221. INCLUDE ([Value]);
  222. PRINT 'Index [IX_HangFire_Counter_Key] re-created';
  223. DROP TABLE [HangFire].[Value];
  224. DROP TABLE [HangFire].[Hash];
  225. PRINT 'Dropped tables [HangFire].[Value] and [HangFire].[Hash]'
  226. DELETE FROM [HangFire].[Server] WHERE [LastHeartbeat] IS NULL;
  227. ALTER TABLE [HangFire].[Server] ALTER COLUMN [LastHeartbeat] DATETIME NOT NULL;
  228. SET @CURRENT_SCHEMA_VERSION = 2;
  229. END
  230. IF @CURRENT_SCHEMA_VERSION = 2
  231. BEGIN
  232. PRINT 'Installing schema version 3';
  233. DROP INDEX [IX_HangFire_JobQueue_JobIdAndQueue] ON [HangFire].[JobQueue];
  234. PRINT 'Dropped index [IX_HangFire_JobQueue_JobIdAndQueue]';
  235. CREATE TABLE [HangFire].[Hash](
  236. [Id] [int] IDENTITY(1,1) NOT NULL,
  237. [Key] [nvarchar](100) NOT NULL,
  238. [Field] [nvarchar](100) NOT NULL,
  239. [Value] [nvarchar](max) NULL,
  240. [ExpireAt] [datetime2](7) NULL,
  241. CONSTRAINT [PK_HangFire_Hash] PRIMARY KEY CLUSTERED ([Id] ASC)
  242. );
  243. PRINT 'Created table [HangFire].[Hash]';
  244. CREATE UNIQUE NONCLUSTERED INDEX [UX_HangFire_Hash_Key_Field] ON [HangFire].[Hash] (
  245. [Key] ASC,
  246. [Field] ASC
  247. );
  248. PRINT 'Created index [UX_HangFire_Hash_Key_Field]';
  249. SET @CURRENT_SCHEMA_VERSION = 3;
  250. END
  251. IF @CURRENT_SCHEMA_VERSION = 3
  252. BEGIN
  253. PRINT 'Installing schema version 4';
  254. CREATE TABLE [HangFire].[AggregatedCounter] (
  255. [Id] [int] IDENTITY(1,1) NOT NULL,
  256. [Key] [nvarchar](100) NOT NULL,
  257. [Value] [bigint] NOT NULL,
  258. [ExpireAt] [datetime] NULL,
  259. CONSTRAINT [PK_HangFire_CounterAggregated] PRIMARY KEY CLUSTERED ([Id] ASC)
  260. );
  261. PRINT 'Created table [HangFire].[AggregatedCounter]';
  262. CREATE UNIQUE NONCLUSTERED INDEX [UX_HangFire_CounterAggregated_Key] ON [HangFire].[AggregatedCounter] (
  263. [Key] ASC
  264. ) INCLUDE ([Value]);
  265. PRINT 'Created index [UX_HangFire_CounterAggregated_Key]';
  266. CREATE NONCLUSTERED INDEX [IX_HangFire_Hash_ExpireAt] ON [HangFire].[Hash] ([ExpireAt])
  267. INCLUDE ([Id]);
  268. CREATE NONCLUSTERED INDEX [IX_HangFire_Job_ExpireAt] ON [HangFire].[Job] ([ExpireAt])
  269. INCLUDE ([Id]);
  270. CREATE NONCLUSTERED INDEX [IX_HangFire_List_ExpireAt] ON [HangFire].[List] ([ExpireAt])
  271. INCLUDE ([Id]);
  272. CREATE NONCLUSTERED INDEX [IX_HangFire_Set_ExpireAt] ON [HangFire].[Set] ([ExpireAt])
  273. INCLUDE ([Id]);
  274. PRINT 'Created indexes for [ExpireAt] columns';
  275. CREATE NONCLUSTERED INDEX [IX_HangFire_Hash_Key] ON [HangFire].[Hash] ([Key] ASC)
  276. INCLUDE ([ExpireAt]);
  277. PRINT 'Created index [IX_HangFire_Hash_Key]';
  278. CREATE NONCLUSTERED INDEX [IX_HangFire_List_Key] ON [HangFire].[List] ([Key] ASC)
  279. INCLUDE ([ExpireAt], [Value]);
  280. PRINT 'Created index [IX_HangFire_List_Key]';
  281. CREATE NONCLUSTERED INDEX [IX_HangFire_Set_Key] ON [HangFire].[Set] ([Key] ASC)
  282. INCLUDE ([ExpireAt], [Value]);
  283. PRINT 'Created index [IX_HangFire_Set_Key]';
  284. SET @CURRENT_SCHEMA_VERSION = 4;
  285. END
  286. IF @CURRENT_SCHEMA_VERSION = 4
  287. BEGIN
  288. PRINT 'Installing schema version 5';
  289. DROP INDEX [IX_HangFire_JobQueue_QueueAndFetchedAt] ON [HangFire].[JobQueue];
  290. PRINT 'Dropped index [IX_HangFire_JobQueue_QueueAndFetchedAt] to modify the [HangFire].[JobQueue].[Queue] column';
  291. ALTER TABLE [HangFire].[JobQueue] ALTER COLUMN [Queue] NVARCHAR (50) NOT NULL;
  292. PRINT 'Modified [HangFire].[JobQueue].[Queue] length to 50';
  293. CREATE NONCLUSTERED INDEX [IX_HangFire_JobQueue_QueueAndFetchedAt] ON [HangFire].[JobQueue] (
  294. [Queue] ASC,
  295. [FetchedAt] ASC
  296. );
  297. PRINT 'Re-created index [IX_HangFire_JobQueue_QueueAndFetchedAt]';
  298. ALTER TABLE [HangFire].[Server] DROP CONSTRAINT [PK_HangFire_Server]
  299. PRINT 'Dropped constraint [PK_HangFire_Server] to modify the [HangFire].[Server].[Id] column';
  300. ALTER TABLE [HangFire].[Server] ALTER COLUMN [Id] NVARCHAR (100) NOT NULL;
  301. PRINT 'Modified [HangFire].[Server].[Id] length to 100';
  302. ALTER TABLE [HangFire].[Server] ADD CONSTRAINT [PK_HangFire_Server] PRIMARY KEY CLUSTERED
  303. (
  304. [Id] ASC
  305. );
  306. PRINT 'Re-created constraint [PK_HangFire_Server]';
  307. SET @CURRENT_SCHEMA_VERSION = 5;
  308. END
  309. IF @CURRENT_SCHEMA_VERSION = 5 AND @DISABLE_HEAVY_MIGRATIONS = 1
  310. BEGIN
  311. PRINT 'Migration process STOPPED at schema version ' + CAST(@CURRENT_SCHEMA_VERSION AS NVARCHAR) +
  312. '. WILL NOT upgrade to schema version ' + CAST(@TARGET_SCHEMA_VERSION AS NVARCHAR) +
  313. ', because @DISABLE_HEAVY_MIGRATIONS option is set.';
  314. END
  315. ELSE IF @CURRENT_SCHEMA_VERSION = 5
  316. BEGIN
  317. PRINT 'Installing schema version 6';
  318. -- First, we will drop all the secondary indexes on the HangFire.Set table, because we will
  319. -- modify that table, and unknown indexes may be added there (see https://github.com/HangfireIO/Hangfire/issues/844).
  320. -- So, we'll drop all of them, and then re-create the required index with a well-known name.
  321. DECLARE @dropIndexSql NVARCHAR(MAX) = N'';
  322. SELECT @dropIndexSql += N'DROP INDEX ' + QUOTENAME(SCHEMA_NAME(o.[schema_id])) + '.' + QUOTENAME(o.name) + '.' + QUOTENAME(i.name) + ';'
  323. FROM sys.indexes AS i
  324. INNER JOIN sys.tables AS o
  325. ON i.[object_id] = o.[object_id]
  326. WHERE i.is_primary_key = 0
  327. AND i.index_id <> 0
  328. AND o.is_ms_shipped = 0
  329. AND SCHEMA_NAME(o.[schema_id]) = 'HangFire'
  330. AND o.name = 'Set';
  331. EXEC sp_executesql @dropIndexSql;
  332. PRINT 'Dropped all secondary indexes on the [Set] table';
  333. -- Next, we'll remove the unnecessary indexes. They were unnecessary in the previous schema,
  334. -- and are unnecessary in the new schema as well. We'll not re-create them.
  335. DROP INDEX [IX_HangFire_Hash_Key] ON [HangFire].[Hash];
  336. PRINT 'Dropped unnecessary index [IX_HangFire_Hash_Key]';
  337. -- Next, all the indexes that cover expiration will be filtered, to include only non-null values. This
  338. -- will prevent unnecessary index modifications – we are seeking these indexes only for non-null
  339. -- expiration time. Also, they include the Id column by a mistake. So we'll re-create them later in the
  340. -- migration.
  341. DROP INDEX [IX_HangFire_Hash_ExpireAt] ON [HangFire].[Hash];
  342. PRINT 'Dropped index [IX_HangFire_Hash_ExpireAt]';
  343. DROP INDEX [IX_HangFire_Job_ExpireAt] ON [HangFire].[Job];
  344. PRINT 'Dropped index [IX_HangFire_Job_ExpireAt]';
  345. DROP INDEX [IX_HangFire_List_ExpireAt] ON [HangFire].[List];
  346. PRINT 'Dropped index [IX_HangFire_List_ExpireAt]';
  347. -- IX_HangFire_Job_StateName index can also be optimized, since we are querying it only with a
  348. -- non-null state name. This will decrease the number of operations, when creating a background job.
  349. -- It will be recreated later in the migration.
  350. DROP INDEX [IX_HangFire_Job_StateName] ON [HangFire].Job;
  351. PRINT 'Dropped index [IX_HangFire_Job_StateName]';
  352. -- Dropping foreign key constraints based on the JobId column, because we need to modify the underlying
  353. -- column type of the clustered index to BIGINT. We'll recreate them later in the migration.
  354. ALTER TABLE [HangFire].[JobParameter] DROP CONSTRAINT [FK_HangFire_JobParameter_Job];
  355. PRINT 'Dropped constraint [FK_HangFire_JobParameter_Job]';
  356. ALTER TABLE [HangFire].[State] DROP CONSTRAINT [FK_HangFire_State_Job];
  357. PRINT 'Dropped constraint [FK_HangFire_State_Job]';
  358. -- We are going to create composite clustered indexes that are more natural for the following tables,
  359. -- so the following indexes will be unnecessary. Natural sorting will keep related data close to each
  360. -- other, and simplify the index modifications by the cost of fragmentation and additional page splits.
  361. DROP INDEX [UX_HangFire_CounterAggregated_Key] ON [HangFire].[AggregatedCounter];
  362. PRINT 'Dropped index [UX_HangFire_CounterAggregated_Key]';
  363. DROP INDEX [IX_HangFire_Counter_Key] ON [HangFire].[Counter];
  364. PRINT 'Dropped index [IX_HangFire_Counter_Key]';
  365. DROP INDEX [IX_HangFire_JobParameter_JobIdAndName] ON [HangFire].[JobParameter];
  366. PRINT 'Dropped index [IX_HangFire_JobParameter_JobIdAndName]';
  367. DROP INDEX [IX_HangFire_JobQueue_QueueAndFetchedAt] ON [HangFire].[JobQueue];
  368. PRINT 'Dropped index [IX_HangFire_JobQueue_QueueAndFetchedAt]';
  369. DROP INDEX [UX_HangFire_Hash_Key_Field] ON [HangFire].[Hash];
  370. PRINT 'Dropped index [UX_HangFire_Hash_Key_Field]';
  371. DROP INDEX [IX_HangFire_List_Key] ON [HangFire].[List];
  372. PRINT 'Dropped index [IX_HangFire_List_Key]';
  373. DROP INDEX [IX_HangFire_State_JobId] ON [HangFire].[State];
  374. PRINT 'Dropped index [IX_HangFire_State_JobId]';
  375. -- Then, we need to drop the primary key constraints, to modify id columns to the BIGINT type. Some of them
  376. -- will be re-created later in the migration. But some of them would be removed forever, because their
  377. -- uniqueness property sometimes unnecessary.
  378. ALTER TABLE [HangFire].[AggregatedCounter] DROP CONSTRAINT [PK_HangFire_CounterAggregated];
  379. PRINT 'Dropped constraint [PK_HangFire_CounterAggregated]';
  380. ALTER TABLE [HangFire].[Counter] DROP CONSTRAINT [PK_HangFire_Counter];
  381. PRINT 'Dropped constraint [PK_HangFire_Counter]';
  382. ALTER TABLE [HangFire].[Hash] DROP CONSTRAINT [PK_HangFire_Hash];
  383. PRINT 'Dropped constraint [PK_HangFire_Hash]';
  384. ALTER TABLE [HangFire].[Job] DROP CONSTRAINT [PK_HangFire_Job];
  385. PRINT 'Dropped constraint [PK_HangFire_Job]';
  386. ALTER TABLE [HangFire].[JobParameter] DROP CONSTRAINT [PK_HangFire_JobParameter];
  387. PRINT 'Dropped constraint [PK_HangFire_JobParameter]';
  388. ALTER TABLE [HangFire].[JobQueue] DROP CONSTRAINT [PK_HangFire_JobQueue];
  389. PRINT 'Dropped constraint [PK_HangFire_JobQueue]';
  390. ALTER TABLE [HangFire].[List] DROP CONSTRAINT [PK_HangFire_List];
  391. PRINT 'Dropped constraint [PK_HangFire_List]';
  392. ALTER TABLE [HangFire].[Set] DROP CONSTRAINT [PK_HangFire_Set];
  393. PRINT 'Dropped constraint [PK_HangFire_Set]';
  394. ALTER TABLE [HangFire].[State] DROP CONSTRAINT [PK_HangFire_State];
  395. PRINT 'Dropped constraint [PK_HangFire_State]';
  396. -- We are removing identity columns of the following tables completely, their clustered
  397. -- index will be based on natural values. So, instead of modifying them to BIGINT, we
  398. -- are dropping them.
  399. ALTER TABLE [HangFire].[AggregatedCounter] DROP COLUMN [Id];
  400. PRINT 'Dropped [AggregatedCounter].[Id] column, we will cluster on [Key] column with uniqufier';
  401. ALTER TABLE [HangFire].[Counter] DROP COLUMN [Id];
  402. PRINT 'Dropped [Counter].[Id] column, we will cluster on [Key] column';
  403. ALTER TABLE [HangFire].[Hash] DROP COLUMN [Id];
  404. PRINT 'Dropped [Hash].[Id] column, we will cluster on [Key]/[Field] columns';
  405. ALTER TABLE [HangFire].[Set] DROP COLUMN [Id];
  406. PRINT 'Dropped [Set].[Id] column, we will cluster on [Key]/[Value] columns';
  407. ALTER TABLE [HangFire].[JobParameter] DROP COLUMN [Id];
  408. PRINT 'Dropped [JobParameter].[Id] column, we will cluster on [JobId]/[Name] columns';
  409. -- Then we need to modify all the remaining Id columns to be of type BIGINT.
  410. ALTER TABLE [HangFire].[List] ALTER COLUMN [Id] BIGINT NOT NULL;
  411. PRINT 'Modified [List].[Id] type to BIGINT';
  412. ALTER TABLE [HangFire].[Job] ALTER COLUMN [Id] BIGINT NOT NULL;
  413. PRINT 'Modified [Job].[Id] type to BIGINT';
  414. ALTER TABLE [HangFire].[Job] ALTER COLUMN [StateId] BIGINT NULL;
  415. PRINT 'Modified [Job].[StateId] type to BIGINT';
  416. ALTER TABLE [HangFire].[JobParameter] ALTER COLUMN [JobId] BIGINT NOT NULL;
  417. PRINT 'Modified [JobParameter].[JobId] type to BIGINT';
  418. ALTER TABLE [HangFire].[JobQueue] ALTER COLUMN [JobId] BIGINT NOT NULL;
  419. PRINT 'Modified [JobQueue].[JobId] type to BIGINT';
  420. ALTER TABLE [HangFire].[State] ALTER COLUMN [Id] BIGINT NOT NULL;
  421. PRINT 'Modified [State].[Id] type to BIGINT';
  422. ALTER TABLE [HangFire].[State] ALTER COLUMN [JobId] BIGINT NOT NULL;
  423. PRINT 'Modified [State].[JobId] type to BIGINT';
  424. ALTER TABLE [HangFire].[Counter] ALTER COLUMN [Value] INT NOT NULL;
  425. PRINT 'Modified [Counter].[Value] type to INT';
  426. -- Adding back all the Primary Key constraints or clustered indexes where PKs aren't appropriate.
  427. ALTER TABLE [HangFire].[AggregatedCounter] ADD CONSTRAINT [PK_HangFire_CounterAggregated] PRIMARY KEY CLUSTERED (
  428. [Key] ASC
  429. );
  430. PRINT 'Re-created constraint [PK_HangFire_CounterAggregated]';
  431. CREATE CLUSTERED INDEX [CX_HangFire_Counter] ON [HangFire].[Counter] ([Key]);
  432. PRINT 'Created clustered index [CX_HangFire_Counter]';
  433. ALTER TABLE [HangFire].[Hash] ADD CONSTRAINT [PK_HangFire_Hash] PRIMARY KEY CLUSTERED (
  434. [Key] ASC,
  435. [Field] ASC
  436. );
  437. PRINT 'Re-created constraint [PK_HangFire_Hash]';
  438. ALTER TABLE [HangFire].[Job] ADD CONSTRAINT [PK_HangFire_Job] PRIMARY KEY CLUSTERED ([Id] ASC);
  439. PRINT 'Re-created constraint [PK_HangFire_Job]';
  440. ALTER TABLE [HangFire].[JobParameter] ADD CONSTRAINT [PK_HangFire_JobParameter] PRIMARY KEY CLUSTERED (
  441. [JobId] ASC,
  442. [Name] ASC
  443. );
  444. PRINT 'Re-created constraint [PK_HangFire_JobParameter]';
  445. ALTER TABLE [HangFire].[JobQueue] ADD CONSTRAINT [PK_HangFire_JobQueue] PRIMARY KEY CLUSTERED (
  446. [Queue] ASC,
  447. [Id] ASC
  448. );
  449. PRINT 'Re-created constraint [PK_HangFire_JobQueue]';
  450. ALTER TABLE [HangFire].[List] ADD CONSTRAINT [PK_HangFire_List] PRIMARY KEY CLUSTERED (
  451. [Key] ASC,
  452. [Id] ASC
  453. );
  454. PRINT 'Re-created constraint [PK_HangFire_List]';
  455. ALTER TABLE [HangFire].[Set] ADD CONSTRAINT [PK_HangFire_Set] PRIMARY KEY CLUSTERED (
  456. [Key] ASC,
  457. [Value] ASC
  458. );
  459. PRINT 'Re-created constraint [PK_HangFire_Set]';
  460. ALTER TABLE [HangFire].[State] ADD CONSTRAINT [PK_HangFire_State] PRIMARY KEY CLUSTERED (
  461. [JobId] ASC,
  462. [Id]
  463. );
  464. PRINT 'Re-created constraint [PK_HangFire_State]';
  465. -- Creating secondary, nonclustered indexes
  466. CREATE NONCLUSTERED INDEX [IX_HangFire_Job_StateName] ON [HangFire].[Job] ([StateName])
  467. WHERE [StateName] IS NOT NULL;
  468. PRINT 'Re-created index [IX_HangFire_Job_StateName]';
  469. CREATE NONCLUSTERED INDEX [IX_HangFire_Set_Score] ON [HangFire].[Set] ([Score])
  470. WHERE [Score] IS NOT NULL;
  471. PRINT 'Created index [IX_HangFire_Set_Score]';
  472. CREATE NONCLUSTERED INDEX [IX_HangFire_Server_LastHeartbeat] ON [HangFire].[Server] ([LastHeartbeat]);
  473. PRINT 'Created index [IX_HangFire_Server_LastHeartbeat]';
  474. -- Creating filtered indexes for ExpireAt columns
  475. CREATE NONCLUSTERED INDEX [IX_HangFire_AggregatedCounter_ExpireAt] ON [HangFire].[AggregatedCounter] ([ExpireAt])
  476. WHERE [ExpireAt] IS NOT NULL;
  477. PRINT 'Created index [IX_HangFire_AggregatedCounter_ExpireAt]';
  478. CREATE NONCLUSTERED INDEX [IX_HangFire_Hash_ExpireAt] ON [HangFire].[Hash] ([ExpireAt])
  479. WHERE [ExpireAt] IS NOT NULL;
  480. PRINT 'Re-created index [IX_HangFire_Hash_ExpireAt]';
  481. CREATE NONCLUSTERED INDEX [IX_HangFire_Job_ExpireAt] ON [HangFire].[Job] ([ExpireAt])
  482. INCLUDE ([StateName])
  483. WHERE [ExpireAt] IS NOT NULL;
  484. PRINT 'Re-created index [IX_HangFire_Job_ExpireAt]';
  485. CREATE NONCLUSTERED INDEX [IX_HangFire_List_ExpireAt] ON [HangFire].[List] ([ExpireAt])
  486. WHERE [ExpireAt] IS NOT NULL;
  487. PRINT 'Re-created index [IX_HangFire_List_ExpireAt]';
  488. CREATE NONCLUSTERED INDEX [IX_HangFire_Set_ExpireAt] ON [HangFire].[Set] ([ExpireAt])
  489. WHERE [ExpireAt] IS NOT NULL;
  490. PRINT 'Re-created index [IX_HangFire_Set_ExpireAt]';
  491. -- Restoring foreign keys
  492. ALTER TABLE [HangFire].[State] ADD CONSTRAINT [FK_HangFire_State_Job] FOREIGN KEY([JobId])
  493. REFERENCES [HangFire].[Job] ([Id])
  494. ON UPDATE CASCADE
  495. ON DELETE CASCADE;
  496. PRINT 'Re-created constraint [FK_HangFire_State_Job]';
  497. ALTER TABLE [HangFire].[JobParameter] ADD CONSTRAINT [FK_HangFire_JobParameter_Job] FOREIGN KEY([JobId])
  498. REFERENCES [HangFire].[Job] ([Id])
  499. ON UPDATE CASCADE
  500. ON DELETE CASCADE;
  501. PRINT 'Re-created constraint [FK_HangFire_JobParameter_Job]';
  502. SET @CURRENT_SCHEMA_VERSION = 6;
  503. END
  504. IF @CURRENT_SCHEMA_VERSION = 6
  505. BEGIN
  506. PRINT 'Installing schema version 7';
  507. DROP INDEX [IX_HangFire_Set_Score] ON [HangFire].[Set];
  508. PRINT 'Dropped index [IX_HangFire_Set_Score]';
  509. CREATE NONCLUSTERED INDEX [IX_HangFire_Set_Score] ON [HangFire].[Set] ([Key], [Score]);
  510. PRINT 'Created index [IX_HangFire_Set_Score] with the proper composite key';
  511. SET @CURRENT_SCHEMA_VERSION = 7;
  512. END
  513. /*IF @CURRENT_SCHEMA_VERSION = 7
  514. BEGIN
  515. PRINT 'Installing schema version 8';
  516. Insert migration here
  517. SET @CURRENT_SCHEMA_VERSION = 8;
  518. END*/
  519. UPDATE [HangFire].[Schema] SET [Version] = @CURRENT_SCHEMA_VERSION
  520. IF @@ROWCOUNT = 0
  521. INSERT INTO [HangFire].[Schema] ([Version]) VALUES (@CURRENT_SCHEMA_VERSION)
  522. PRINT 'Hangfire database schema installed';
  523. COMMIT TRANSACTION;
  524. PRINT 'Hangfire SQL objects installed';