singlestoredb/singlestoredb-laravel

适用于Laravel的SingleStoreDB数据库驱动程序。

v1.5.6 2024-07-26 14:30 UTC

README

Latest Stable Version Total Downloads License PHP Version Require Github Actions status image

本仓库包含官方SingleStoreDB Laravel驱动程序。此驱动程序封装了Laravel的官方MySQL支持,以便更好地与SingleStoreDB协同工作。具体来说,此驱动程序相对于原始Laravel MySQL支持具有以下优势

  • 通过Eloquent扩展,允许通过Eloquent API指定特定的SingleStoreDB功能。有关受支持的功能,请参阅迁移
  • 针对SingleStoreDB、PHP和Laravel版本矩阵进行了集成测试。
  • 支持JSON列
  • 查询生成中的其他兼容性修复

目录

安装

您可以通过composer安装此包

composer require singlestoredb/singlestoredb-laravel

此包需要安装pdo_mysql。如果您不确定,请在运行php -i时查看是否列出了pdo_mysql

使用

要启用驱动程序,请转到您的config/database.php文件,并在connections中为SingleStore创建一个新条目,并将您的default更新为指向该新连接。

[
    'default' => env('DB_CONNECTION', 'singlestore'),

    'connections' => [
        'singlestore' => [
            'driver' => 'singlestore',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_HOST'),
            'port' => env('DB_PORT'),
            'database' => env('DB_DATABASE'),
            'username' => env('DB_USERNAME'),
            'password' => env('DB_PASSWORD'),
            'unix_socket' => env('DB_SOCKET'),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => true,
            'engine' => null,
            'options' => extension_loaded('pdo_mysql') ? array_filter([
                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
                PDO::ATTR_EMULATE_PREPARES => true,
            ]) : [],
        ],
    ]
]

由于SingleStore驱动程序是MySQL驱动程序的扩展,因此您也可以将drivermysql更改为singlestore

如果您想在SingleStore中存储失败的作业,请确保您也将其设置为config/queue.php文件中的database。在这种情况下,您可能更喜欢将DB_CONNECTION='singlestore'设置为环境变量。

'failed' => [
    'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),
    'database' => env('DB_CONNECTION', 'singlestore'),
    'table' => 'failed_jobs',
],

连接到SingleStore托管服务时出现问题

如果您遇到连接到SingleStore托管服务的问题,可能是因为您的环境无法验证用于加密连接的SSL证书。您可以通过下载并手动指定SingleStore证书文件来修复此问题。

  • 在此处下载文件
  • 在Laravel SingleStore连接配置中,将变量PDO::MYSQL_ATTR_SSL_CA指向singlestore_bundle.pem
'options' => extension_loaded('pdo_mysql') ? array_filter([
    PDO::MYSQL_ATTR_SSL_CA => 'path/to/singlestore_bundle.pem',
    PDO::ATTR_EMULATE_PREPARES => true,
]) : [],

持久连接(性能优化)

通常,我们建议在连接到SingleStoreDB时启用PDO::ATTR_PERSISTENT。这是因为与运行许多事务性查询相比,打开新的SingleStoreDB连接非常昂贵。通过使用PDO::ATTR_PERSISTENT,您可以显着提高事务性工作负载的性能。

使用持久连接的唯一缺点是您需要确保正确清理事务,并且当更改会话变量或上下文数据库时必须小心。您可以在php.net的官方文档中了解更多有关此功能的信息

此外,请注意,SingleStoreDB在其默认配置下可以处理大量空闲连接而不会影响性能。默认情况下,每个聚合器大约有100,000个空闲连接,但可以根据服务器的处理能力设置得更高。

要启用此功能,只需更新您的选项,包括 PDO::ATTR_PERSISTENT => true

'options' => extension_loaded('pdo_mysql') ? array_filter([
    PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
    PDO::ATTR_EMULATE_PREPARES => true,
    PDO::ATTR_PERSISTENT => true,
]) : [],

DELETEUPDATE 查询中的 ORDER BY 子句

SingleStore不支持在DELETEUPDATE查询中使用ORDER BY子句。发出类似于以下查询将返回错误。

DB::table('test')->orderBy('id', 'asc')->update(['id' => 1, 'a' => 'b']);
DB::table('test')->orderBy('id', 'asc')->delete();

您可以通过在连接配置中分别启用ignore_order_by_in_deletesignore_order_by_in_updates来配置驱动程序忽略delete()update()请求中的orderBy。例如

[
    'default' => env('DB_CONNECTION', 'singlestore'),

    'connections' => [
        'singlestore' => [
            'driver' => 'singlestore',
            'ignore_order_by_in_deletes' => true,
            'ignore_order_by_in_updates' => true,
            ...
        ],
    ]
]

请注意,当忽略orderBy时,如果查询包含LIMIT或OFFSET,可能会导致删除/更新不同的行。

示例

DB::table('user')->orderBy('score', 'asc')->limit(5)->delete();

在以下查询中忽略ORDER BY时 - 将删除5个随机用户,而不是5个得分最低的用户。

8.1之前的PHP版本

在8.1之前的PHP版本中,PDO::ATTR_EMULATE_PREPARES标志会导致一个bug,该bug导致MySQL(和SingleStoreDB)返回的所有属性都作为字符串返回。

例如,一个名为user_id的列和类型为int(10)的表,如果行值为5423,我们将在PHP中获得类似"5423"的字符串。

这是一个历史性和已知的bug

解决此问题的最佳方法是升级到PHP 8.1或更高版本。如果不可能,请使用Eloquent的属性转换作为下一个最佳解决方案。

迁移

此驱动程序提供了许多用于创建或修改表的SingleStore特定方法。下面列出了它们。有关更多信息,请参阅SingleStore的创建表文档。

通用存储表(列存储)

默认情况下,由该驱动程序创建的表将使用SingleStoreDB通用存储。通用存储利用列和行导向的数据结构来自动优化事务和分析工作负载的存储。一般来说,除非您对工作负载进行了分析并确定其他表类型更好,否则您应该使用此表类型。

要创建一个表,您可以使用Schema::create

Schema::create('table', function (Blueprint $table) {
    // ... column definitions, indexes, table options
});

行存储表

要创建行存储表,请使用rowstore方法。行存储表针对低延迟事务工作负载和高并发进行了优化,但会牺牲内存。一般来说,我们建议使用通用存储(见上文)并在使用行存储表之前对工作负载进行基准测试。

Schema::create('table', function (Blueprint $table) {
    $table->rowstore();

    // ...
});

参考表

要创建参考表,您可以使用reference方法。参考表在集群的每个节点上完全复制。这意味着如果您在参考表中存储1000行,这些1000行将被复制多次。因此,您应仅在需要通过与其他表的非列数据连接来引用该数据时才在参考表中存储少量数据。由于复制开销高,对参考表的插入和更新也将运行得更慢。

Schema::create('table', function (Blueprint $table) {
    $table->reference();

    // ...
});

全局临时表

要创建全局临时表,您可以在表上使用global方法。

Schema::create('table', function (Blueprint $table) {
    $table->rowstore();
    $table->temporary();
    $table->global();

    // ...
});

您还可以使用以下两种方法中的任意一种

// Fluent
$table->rowstore()->temporary()->global();

// As an argument to `temporary`.
$table->temporary($global = true);

稀疏列

您可以通过在列定义后附加 sparse 来流畅地标记特定的列为 稀疏,这仅适用于Rowstore表。

Schema::create('table', function (Blueprint $table) {
    $table->rowstore();

    $table->string('name')->nullable()->sparse();
});

稀疏表

您可以通过在列定义后附加 sparse 来流畅地标记特定的整个表为 稀疏,这仅适用于Rowstore表。

Schema::create('table', function (Blueprint $table) {
    $table->rowstore();

    $table->string('name');

    $table->sparse();
});

分片键

您可以使用独立的 shardKey 方法,或将 shardKey 附加到列定义来为您的表添加一个 分片键

Schema::create('table', function (Blueprint $table) {
    $table->string('name');

    $table->shardKey('name');
});

Schema::create('table', function (Blueprint $table) {
    $table->string('name')->shardKey();
});

Schema::create('table', function (Blueprint $table) {
    $table->string('f_name');
    $table->string('l_name');

    $table->shardKey(['f_name', 'l_name']);
});

排序键

您可以使用独立的 sortKey 方法,或将 sortKey 附加到列定义来为您的表添加一个 排序键

Schema::create('table', function (Blueprint $table) {
    $table->string('name');

    $table->sortKey('name');
});

Schema::create('table', function (Blueprint $table) {
    $table->string('name')->sortKey();
});

Schema::create('table', function (Blueprint $table) {
    $table->string('f_name');
    $table->string('l_name');

    $table->sortKey(['f_name', 'l_name']);
});

默认情况下,排序键按升序排序。如果您想创建一个按降序排序的排序键,可以将键方向设置为 desc

Schema::create('table', function (Blueprint $table) {
    $table->string('name');

    $table->sortKey('name', 'desc');
});

Schema::create('table', function (Blueprint $table) {
    $table->string('name')->sortKey('desc');
});

您还可以使用以下语法按列定义排序键方向

Schema::create('table', function (Blueprint $table) {
    $table->string('f_name');
    $table->string('l_name');

    $table->sortKey([['f_name', 'asc'], ['l_name', 'desc']]);
});

有时您可能想按表对 列存储 进行调整。您可以通过将 with 流畅地附加到 sortKey 定义来实现。

Schema::create('table', function (Blueprint $table) {
    $table->string('name');

    $table->sortKey('name')->with(['columnstore_segment_rows' => 100000]);
});

Schema::create('table', function (Blueprint $table) {
    $table->string('name')->sortKey()->with(['columnstore_segment_rows' => 100000]);
});

但是,您可能希望在未设置列为排序键的情况下进行调整。您可以通过创建一个空的 sortKey 定义来实现这一点。

Schema::create('table', function (Blueprint $table) {
    $table->string('name');

    $table->sortKey()->with(['columnstore_segment_rows' => 100000]);
});

唯一键

您可以使用独立的 unique 方法,或将 unique 附加到列定义来为您的表添加一个 unique key

注意 SingleStore 要求分片键包含在唯一键中。这意味着在大多数情况下,您不能使用流畅的API,因为您可能需要指定多个列。此限制不适用于参考表。

Schema::create('table', function (Blueprint $table) {
    $table->string('key');
    $table->string('val');

    $table->shardKey('key');
    $table->unique(['key', 'val']);
});

Schema::create('table', function (Blueprint $table) {
    $table->reference();
    $table->string('name')->unique();
});

哈希键

您可以使用 index 函数的第三个参数将 hash key 添加到您的表中。请注意,默认情况下,Universal Storage Tables(Columnstore)上的索引始终是哈希索引,所以简单的 .index(foo) 通常就足够了。在Rowstore表上,此语法是创建哈希索引所必需的。

Schema::create('table', function (Blueprint $table) {
    $table->string('name');
    $table->index('name', 'name_idx', 'hash');
});

系列时间戳

要表示一列为一系列时间戳,请使用 seriesTimestamp 列修饰符。

Schema::create('table', function (Blueprint $table) {
    $table->datetime('created_at')->seriesTimestamp();

    // Or make it sparse
    $table->datetime('deleted_at')->nullable()->seriesTimestamp()->sparse();
});

计算列

SingleStore 不支持虚拟计算列。您必须使用 Laravel 的 storedAs 方法来创建一个 持久化计算列

Schema::create('test', function (Blueprint $table) {
    $table->integer('a');
    $table->integer('b');
    $table->integer('c')->storedAs('a + b');
});

无主键的递增列

有时您可能想设置一个自定义主键。但是,如果您的表有一个 int increment 列,Laravel 默认会始终将该列设置为主键。即使您手动设置另一个主键也是如此。您可以使用 withoutPrimaryKey 方法来禁用此行为。

Schema::create('test', function (Blueprint $table) {
    $table->id()->withoutPrimaryKey();
    $table->uuid('uuid');
    
    $table->primary(['id',  'uuid']);
});

使用FULLTEXT索引进行全文搜索

SingleStoreDB 支持在列存储表中的文本列上使用 FULLTEXT 索引类型进行全文搜索。

请注意,FULLTEXT 仅在使用 utf8_unicode_ci 校对时才受支持。如果您尝试将索引添加到不支持校对的列,则会抛出异常。

Schema::create('test', function (Blueprint $table) {
    $table->id();
    $table->text('first_name')->collation('utf8_unicode_ci');

    $table->fullText(['first_name']);
});

测试

使用 PHPUnit 执行测试

./vendor/bin/phpunit

要针对活动 SingleStore 数据库进行测试,创建一个 .env 文件并填充以下变量

DB_DATABASE=
DB_USERNAME=
DB_PASSWORD=
DB_HOST=

现在当执行您的测试时,通过运行以下命令来启用集成测试

HYBRID_INTEGRATION=1 ./vendor/bin/phpunit

兼容性矩阵

许可

此库根据 Apache 2.0 许可证授权。

资源

用户协议

单店科技(“单店”)同意授予您和您的公司访问此开源软件连接器的权限,前提是:(A)您和您的公司代表并保证,您代表您的公司有权依法约束您的公司;(B)您代表您的公司接受并同意受以下开源条款和条件(“本协议”)的约束,该协议将通过以下任何一种方式得到明确证明:您代表您的公司点击“下载”、“接受”或“继续”按钮(如有适用),或公司的安装、访问或使用开源连接器,并自以下较早日期起生效:下载、访问、复制或安装连接器或使用单店提供的任何服务(包括任何更新或升级)的日期。

客户理解并同意,其被授予访问SingleStore开源软件连接器(“Beta Software Connector”)预发布或“beta”版本的权利,仅限于非生产测试和评估此类Beta Software Connector。客户承认,单店没有义务发布此类Beta Software Connector的通用版本,也没有义务为任何生产或非评估用途提供此类Beta Software Connector的支持或保修。

尽管任何文件、协议或任何订单文件中有任何相反规定,单店对本次Beta Software Connector(包括工具和实用程序)不提供任何保证、赔偿、支持或服务级别义务。

适用的开源许可:Apache 2.0

如果您或您的公司不同意这些条款和条件,请不要勾选接受框,并且不要下载、访问、复制、安装或使用软件或服务。