google / uuid

Go package for UUIDs based on RFC 4122 and DCE 1.1: Authentication and Security Services.
BSD 3-Clause "New" or "Revised" License
5.26k stars 362 forks source link

SQL value more efficient at bytes #20

Closed japettyjohn closed 5 years ago

japettyjohn commented 7 years ago

The SQL Value() gives a string representation of UUID, if this is unindexed data this may make little difference in the performance of the data but where this is either an index or even the PK this not efficient storage. Here's one of many articles on it.

This could either have a breaking change and make this provide a []byte type. If there is some more dominant SQL DB being targeted which does not benefit from this, then we could minimally have a BytesValuer() function to return a Valuer which does do this.

ricardofandrade commented 6 years ago

I have an actual issue with the fact String() is used: I support multiple databases and one of them only takes []byte for UUID. In the interest of maintaining backwards compatibility, would a patch introducing a global option (yeah, I know...) be accept to return either String() or byte[]? Something along the lines of uuid.ForceBinaryOutputForSQL(true)

pborman commented 6 years ago

A global option would be bad. It would affect every package's use. You never know who might be depending on this. I will admit I am not a database person and this function was implemented by someone who knew more about databases than me. It seems like maybe a new type is needed that embeds a UUID, though it would break the ability to directly access values:

// A UUID Bytes is a UUID whose sql Value function returns a byte slice rather than a string.
type UUIDBytes struct {
    UUID
}

func (uuid UUIDBytes) Value() (driver.Value, error) {
        return uuid[:], nil
}
ricardofandrade commented 6 years ago

@pborman thanks for the reply. Would you propose this new wrapper type to be part of uuid?

pborman commented 6 years ago

It actually does not need to be part of the UUID package at all. Before adding it to the package it would be good to get some feedback on how easy/hard such a thing would be to use. I think if you never sliced the uuid then you would have no problem. You might also want:

func (uuid UUIDBytes) Bytes() []byte {
    return uuid.UUID[:]
}
ricardofandrade commented 6 years ago

I am doing some experimentation currently. I'll report my findings here. Not sure in which context slicing an UUID prior to storing it to the database would make any sense.

pborman commented 6 years ago

It would be more for passing the UUID to something other than a database function, though I guess the code could simply say id.UUID[:] rather than id.Bytes() to get the byte slice.

ghost commented 6 years ago

Bytes() seems to be pretty common in the Go ecosystem - i'll cast a gentle vote in favor of the above as well

ricardofandrade commented 6 years ago

I held a similar discussion over https://github.com/gofrs/uuid/issues/48 and a lot has been taken into account. The resulting decision was to not take any action since no solution seems adequate to be adopted long term by a UUID package. If you all agree with considerations taken over there, feel free to close this issue.

pborman commented 5 years ago

Thanks Ricardo, I think I will close this.