GUID nonclustered index

Need a globally unique key for a table, but don’t want to risk performance issues arising from a random clustered index? And you don’t want to deal with similar keys by using newsequentialid?

The solution is to make a clustered index out of a regular identity integer, and use a GUID as a nonclustered primary key:

/*
Identity is the clustered index, but not the primary key.

Primary key has a non-clustered index.

The records are physically inserted in the database in order by the clustered key, but the primary key as a random GUID is still indexed.
*/

create table dbo.SomeTable
(
    CX int not null identity
    ,SomeTableKey uniqueidentifier not null
    ,...
);
go
alter table dbo.SomeTable
add constraint PK_SomeTable primary key nonclustered (SomeTableKey);
go
create unique clustered index CIX_SomeTable on dbo.SomeTable (CX);
go
alter table dbo.SomeTable
add constraint DF_SomeTable_Key default (newid()) for SomeTableKey;
go

Javascript GUID

If you need a GUID in Javascript, here are samples for building your own, either in a browser setting, or using NodeJS where you can easily add more features.

In Browser

function createGuid() {
    return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
        var r = Math.random() * 16 | 0, v = c == "x" ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}

NodeJS

Technically this isn’t a proper GUID, but it is 16 cryptographically-pseudorandom bytes and works just fine if you need something that fits into a Guid/Uniqueidentifier or whatever else you’re calling it.

const crypto = require("crypto");

class Guid {

    constructor(hex) {
        if (typeof hex != "string") {
            throw "Must be a string";
        }
        
        var val = hex.replace(/[^0-9a-fA-F]/g, "").toLowerCase();
        if (val.length != 32) {
            throw "Must be 32 hex characters";
        }

        this._hex = val;
    }

    static newGuid() {

        var bytes = crypto.randomBytes(32);

        for (let i = 0; i < 32; ++i) {
            bytes[i] = (bytes[i] / 16) | 0;
        }

        let i = 0;
        let hex = "xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx".replace(/[xy]/g, function (c) {
            var r = bytes[i++], v = c == "x" ? r : (r & 0x3 | 0x8);
            return v.toString(16);
        });
        return new Guid(hex);
    }

    toString(format) {
        format = (format || "D");
        let sub = (start, end) => this._hex.substring(start, end);
        switch (format) {
            case "N": return this._hex.toUpperCase();
            case "n": return this._hex;
            case "D": return (`${sub(0, 8)}-${sub(8, 12)}-${sub(12, 16)}-${sub(16, 20)}-${sub(20, 32)}`).toUpperCase();
            case "d": return (`${sub(0, 8)}-${sub(8, 12)}-${sub(12, 16)}-${sub(16, 20)}-${sub(20, 32)}`);
        }
    }
}

module.exports = Guid;