berlindb / core

All of the required core code
MIT License
252 stars 27 forks source link

Primary Column Can't Be String #124

Closed spencerfinnell closed 2 years ago

spencerfinnell commented 2 years ago

When setting a primary column if the type of column is not an int, tinyint, etc, queries will not work. get_item_ids() always uses wp_parse_id_list which forces an integer value. This will destroy non-integer results.

Use case: Stripe object IDs are strings and it would be ideal to use those as the primary column when tracking the objects internally.

spencerfinnell commented 2 years ago

This also happens again in set_items() and shape_item_id().

JJJ commented 2 years ago

Most of Berlin is designed with the idea that the primary column is always numeric and auto-incrementing.

Stripe object IDs are strings and it would be ideal to use those as the primary column when tracking the objects internally.

Why is that ideal? I think I would still want/suggest a traditional numeric auto-incrementing id column as the primary key, and then add the Stripe object ID as the next indexed string column. What do you think?

Using auto-incrementing IDs in SQL brings some benefits:

An obvious point against numeric/autoincrement is what happened at Mt Gox back in the day.

spencerfinnell commented 2 years ago

@JJJ That all seems reasonable. I guess my main thinking was that I will always know the Stripe object ID so I can use it immediately on update and delete calls without first finding the relevant row via the Stripe object ID so I can then use auto incremented primary key.

i.e

$coupon = get_coupon_by( 'object_id', $object_id );
$db->delete_item( $coupon->id );

vs.

$db->delete_item( $object_id );

Is there enough caching in play where that doesn't matter? Or are the performance implications of a string based primary key worse?

alexstandiford commented 2 years ago

You can also set the stripe ID as a key in your table schema, so you'd get similar speed benefits if it were the primary key.

If you want to be able to delete a record using the Stripe object ID, I would consider extending the delete method to support the stripe ID, or create a a different method specifically for that.

I know it seems wasteful to have to fetch the record from the DB first, but that happens inside Berlin regardless, and it's caching mechanism is smart enough to only query once. It shouldn't have any significant impact on performance, but you still get the benefits mentioned by @JJJ

ashleyfae commented 2 years ago

You could just use wpdb directly to delete in that instance. Their delete method supports a where clause.

$wpdb->delete( $table_name, array( 'object_id' => $object_id ), array( '%s' ) );

Translates into:

DELETE FROM my_table WHERE object_id = 'sub_123';
alexstandiford commented 2 years ago

What @ashleyfae is suggesting might be better, but it doesn't clear the item's cache. Make sure you take a look at the delete item method to see how it handles updating the cache for the record otherwise you'll end up with unexpected results should you make another query for that record in the same request.

spencerfinnell commented 2 years ago

Thanks for the tips/info @ashleyfae and @alexstandiford. As with most things, after rethinking things a bit, I think I can get by with a "normal" primary key without issue. It would be nice to document this expected behavior or throw an error when things are misconfigured, similar to some of the object properties. I had to dig down a bit to see where/why things were failing.

JJJ commented 2 years ago

It would be nice to document this expected behavior or throw an error when things are misconfigured

Noted. Great feedback. 👍

JJJ commented 2 years ago

PR #140 merged a few enhancements for 2.1.0:

See #130 for discussion and work towards improving delete_item() 👍