delete 订阅
delete是指删除,常用于编程语言中(C++,SQL等等)。过去式:deleted;过去分词:deleted;现在分词:deleting;第三人称单数:deletes 展开全文
delete是指删除,常用于编程语言中(C++,SQL等等)。过去式:deleted;过去分词:deleted;现在分词:deleting;第三人称单数:deletes
信息
外文名
delete
现在分词
deleting
过去式
deleted
中文名
删除
应用领域
编程
delete基本信息
/di`li:t/v.tr.remove or obliterate(written or printed matter),通过esp.by striking out(尤指划掉)删除,删去(手写话印刷内容)[Latin delēre delet-'efface']对于文件名shift+delete可彻底删除。按住 SHIFT 键再单击“关闭”按钮(一般适用)
收起全文
精华内容
下载资源
问答
  • c++ new delete知识总结

    千次阅读 2017-07-12 16:16:33
    c++ new delete 局部重载 全局重载

    一、C++的动态对象创建

    当创建一个C++对象时,会发生两件事:
    (1)为对象分配内存
    (2)调用构造函数来初始化那个内存

    然而,为对象分配内存可以用以下几种方式或在可选择的时间发生:
    (1)在静态存储区域,存储空间在程序开始之前就可以分配。这个存储空间在整个运行期间都存在。
    (2)无论何时到达一个特殊的执行点(左大括号)时,存储单元都可以在栈上被创建。出了执行点(右大括号),这个存储单元自动被释放。这些栈分配运算内置于处理器的指令集中,非常有效。但是,在写程序的时候,必须知道需要多少个存储单元,以便编译器知道生成正确的指令。
    (3)存储单元也可以从一块称为堆的地方分配。这被称为动态内存分配。在运行时调用程序分配这些内存。这就意味着在任何时候可以分配内存以及分配多少内存,当然也需要负责决定何时释放内存。

    二、C++的new 和 delete

    C++中的解决方法是把创建一个对象所需的所有动作都结合在一个称为new的运算符里。我们当用new创建一个对象时,它就在堆里为对象分配内存并为这块内存调用构造函数。我们可以为类使用任何可用的构造函数,如果构造函数没有参数,可以写没有构造函数参数表的new表达式。

    new表达式的反面是delete表达式。delete表达式首先调用析构函数,然后释放内存。如果正在删除的对象的指针是0,将不发生任何事情。为此,我们经常建议在删除指针后立即把指针赋值为0以免对它删除两次,从而产生某些问题。

    #include <iostream>
    
    using namespace std;
    
    class B{
    public:
         B(){
            cout<<"class b is created"<<endl;
        }
        ~B(){
            cout<<"class b is deleted"<<endl;
        }
    
    };
    
    int main(){
    
        B *a=new B;
    
        delete a;
        cout<<"-----------------"<<endl;
    
        B *b=new B[3];
    
        //空的方括号告诉编译器产生代码,该代码的任务是将从数组创建时存放在某处的对象数量取回,并为数组的所有对象调用析构函数。
        delete []b;
    }
    
    最终打印结果为:
    class b is created
    class b is deleted
    -----------------
    class b is created
    class b is created
    class b is created
    class b is deleted
    class b is deleted
    class b is deleted
    

    三、重载局部new delete

    重载的new必须有一个size_t参数(不管是局部new还是全局new,不管是new 还是new[])。这个参数由编译器产生并传递给我们,它是要分配内存的对象的长度。必须返回一个指向等于这个长度(或者大于这个长度)的对象的指针。我们首先需要明白的一点就是:operator new()的返回值是一个void*。它所做的是分配内存,而不是完成一个对象建立–直到构造函数调用了才完成对象的创建,它是编译器确保做的动作,不在我们的控制范围之内了,所以我们就没有必要考虑。

    当在一个类内部重载new和delete的时候,我们称之为重载局部new delete。为一个类重载new和delete的时候,尽管不必显式的使用static,但是实际上仍是在创建static成员函数。它的语法也和重载任何其它运算符一样。当编译器看到使用new创建自己定义的类的对象时,它会选择相应版本的局部new delete函数去执行。

    #include <iostream>
    
    using namespace std;
    
    class A{
    public:
        static int count;
    
        A(){
        cout<<"class a is created"<<endl;
        }
        ~A(){
            cout<<"class a is deleted"<<endl;
        }
    
        //局部new重载
        /*注意:当执行A *a=new A时,会先调用这个局部new重载函数,然后调用了2次构造函数,但返回的对象的内存地址却是相同的一个,因此可以理解为只创建了一个对象,不知道为啥会调用2次构造函数。*/
        static void * operator new(size_t size){
            cout<<"jubu new is called"<<endl;
            count++;
            A *a=::new A;
    
            return a;
        }
    
        //局部delete重载
        static void operator delete(void *p){
            cout<<"jubu delete is called "<<p<<endl;
            count--;
            ::delete p;
    
        }
    
        //局部new[]重载
        static void * operator new[](size_t size){
            cout<<"jubu [] new is called"<<endl;
    
            return operator new(size);
        }
    
        //局部delete[]重载
        static void operator delete[](void *p){
            cout<<"jubu [] delete is called"<<endl;
            operator delete(p);
        }
    };
    
    int A::count=0;
    
    
    
    int main(){
        A *a=new A;//调用局部重载new
        delete a;//调用局部重载delete
        cout<<"-----------------"<<endl;
    
        A *b=new A[3];//调用局部重载new[]
        delete []b;//调用局部重载delete[]
    }
    上述程序输出结果为:
    jubu new is called
    class a is created   
    class a is created
    class a is deleted
    jubu delete is called 0x7111a0
    -----------------
    jubu [] new is called
    jubu new is called
    class a is created
    class a is created
    class a is created
    class a is created
    class a is deleted
    class a is deleted
    class a is deleted
    jubu [] delete is called
    jubu delete is called 0x7111a0
    

    四、全局new delete重载

    全局new delete重载,即相关的重载方法,写在和main方法同级的代码块中,针对整个系统有效,而上述局部new delete重载只是针对本类有效。

    #include <iostream>
    
    using namespace std;
    
    class A{
    public:
        static int count;
    
        A(){
            cout<<"class a is created"<<endl;
        }
        ~A(){
            cout<<"class a is deleted"<<endl;
        }
    
        //局部new重载
        static void * operator new(size_t size){
            cout<<"jubu new is called"<<endl;
            count++;
            A *a=::new A;
    
            return a;
        }
    
        //局部delete重载
        static void operator delete(void *p){
            cout<<"jubu delete is called "<<p<<endl;
            count--;
            ::delete p;
    
        }
    
        //局部new重载
        static void * operator new[](size_t size){
            cout<<"jubu [] new is called"<<endl;
    
            return operator new(size);
        }
    
        //局部delete重载
        static void operator delete[](void *p){
            cout<<"jubu [] delete is called"<<endl;
            operator delete(p);
        }
    };
    
    int A::count=0;
    
    //全局new重载
    void * operator new(size_t size){
        if(size==0){
            return 0;
        }
        void *p=malloc(size);
        cout<<"quanju new is called "<<p<<endl;
        return p;
    }
    //全局new[]重载
    void * operator new[](size_t size){
        cout<<"quanju[] new is called "<<endl;
        return operator new(size);
    }
    //全局delete重载
    void operator delete(void *p){
        cout<<"quanju delete is called "<<p<<endl;
        free(p);
    }
    //全局delete[]重载
    void operator delete[](void *p){
        cout<<"quanju[] delete is called "<<p<<endl;
        operator delete(p);
    }
    
    int main(){
        int *x=new int(12);
        delete x;
        cout<<"----------"<<endl;
    
        int *p=new int[10];
        delete []p;
        cout<<"-----------------"<<endl;
    
        A *a=new A;
        delete a;
        cout<<"-----------------"<<endl;
    
        A *b=new A[3];
        delete []b;
    }
    上述程序执行结果为:
    //int *x=new int(12);
    //delete x;
    quanju new is called 0x1e11a0
    quanju delete is called 0x1e11a0
    ----------
    //int *p=new int[10];
    //delete []p;
    quanju[] new is called
    quanju new is called 0x1e11a0
    quanju[] delete is called 0x1e11a0
    quanju delete is called 0x1e11a0
    -----------------
    //A *a=new A;
    //delete a;
    jubu new is called
    quanju new is called 0x1e11a0
    class a is created
    class a is created
    class a is deleted
    jubu delete is called 0x1e11a0
    quanju delete is called 0x1e11a0
    -----------------
    //A *a=new A[3];
    //delete []a;
    jubu [] new is called
    jubu new is called
    quanju new is called 0x1e11a0
    class a is created
    class a is created
    class a is created
    class a is created
    class a is deleted
    class a is deleted
    class a is deleted
    jubu [] delete is called
    jubu delete is called 0x1e11a0
    quanju delete is called 0x1e11a0
    

    五、总结

    当局部、全局new delete都被重载后,其和构造方法、析构方法的调用是有顺序的,具体如下图所示:
    这里写图片描述

    展开全文
  • sql delete语句_SQL Delete语句概述

    千次阅读 2020-07-25 13:57:24
    sql delete语句 This article on the SQL Delete is a part of the SQL essential series on key statements, functions and operations in SQL Server. 有关SQL Delete的这篇文章是有关SQL Server中关键语句...

    sql delete语句

    This article on the SQL Delete is a part of the SQL essential series on key statements, functions and operations in SQL Server.

    有关SQL Delete的这篇文章是有关SQL Server中关键语句,函数和操作SQL基本系列的一部分。

    To remove a row from a table is accomplished through a Data Manipulation Language, aka DML statement, using the delete keyword. The SQL delete operation is by far the simplest of all the DML commands. On execution of the delete command, we don’t have to worry about getting any form of data from the table, and we don’t have to worry about working with any data that we get back from the table(s). We just simply tell the database to delete a specific record, and it either does or it doesn’t. It’s that simple.

    从表中删除行是通过数据操作语言(又称DML语句)使用delete关键字完成的。 到目前为止,SQL删除操作是所有DML命令中最简单的操作。 在执行delete命令时,我们不必担心从表中获取任何形式的数据,也不必担心处理从表中获取的任何数据。 我们只是简单地告诉数据库删除特定记录,它要么执行,要么不执行。 就这么简单。

    First, let’s quickly review what an SQL delete statement looks like. We need to tell the database and table from where it should delete the data. It’s a good idea to add a condition clause to set the scope of data deletion. Otherwise, it will delete everything in the table.

    首先,让我们快速回顾一下SQL delete语句的外观。 我们需要告诉数据库和表应从何处删除数据。 添加条件子句以设置数据删除的范围是一个好主意。 否则,它将删除表中的所有内容。

    Let’s take a look at our table and removing some records.

    让我们看一下表并删除一些记录。

    如何删除不带where子句的行 (How to delete rows with no where clause)

    The following example deletes all rows from the Person.Person the table in the AdventureWorks2014 database. There is no restriction enforced on the SQL delete statement using a WHERE clause.

    下面的示例从AdventureWorks2014数据库中的Person.Person表中删除所有行 。 使用WHERE子句SQL delete语句没有任何限制。

    USE Adventureworks2014;
    GO
    DELETE FROM [Person].[Person];
    

    如何使用where子句删除行 (How to delete rows with where clause)

    The following example deletes rows from the [Person].[Person] table in the AdventureWorks2014 database in which the value in the businessEntityID column is greater than 30,000

    以下示例从AdventureWorks2014数据库的[Person]。[Person]表中删除行,其中businessEntityID列中的值大于30,000

    USE Adventureworks2014;
    GO
    DELETE FROM [Person].[Person]
    WHERE businessEntityID > 30000;
    

    Note: An unfortunate mistake that may occur is to accidently run a SQL Delete with no Where clause and inadvertently delete all of your data. To prevent this from happening consider using the Execution guard feature in ApexSQL Complete, to warn against such potentially damaging actions, before you execute them. Learn more: Execution alerts

    注意:可能发生的不幸错误是意外地运行了不带Where子句SQL Delete并无意间删除了所有数据。 为防止这种情况发生,请在执行之前考虑使用ApexSQL Complete中的Execution保护功能,以警告此类可能有害的操作。 了解更多: 执行警报

    如何使用带有where子句的Top删除行 (How to delete rows using Top with where clause)

    The following example deletes 50 random rows from the Person.Person table in the AdventureWorks2014 database. The value in the BusinessEntityID must be in between 30,000 and 40,000

    下面的示例从AdventureWorks2014数据库的Person.Person表中删除50个随机行。 BusinessEntityID中的值必须介于30,000和40,000之间

    USE Adventureworks2014;
    GO
    DELETE TOP(50) FROM [Person].[Person]
    WHERE BusinessEntityID between 30000 and 40000
    

    Note: The when the TOP (n) clause is used with the SQL Delete statement and any DML statement (i.e. Select, Insert, Delete and Update), the operation is performed on a random selection of a number of rows specified in the Top clause.

    注意:当TOP(n)子句与SQL Delete语句和任何DML语句(即Select,Insert,Delete和Update)一起使用时,将对Top子句中指定的许多行的随机选择执行操作。

    如何删除重复的行 (How to delete duplicate rows)

    In the real-world, we tend to gather data from different sources; it’s not uncommon to have duplicate records. One approach to the duplicate problem is first to identify where the duplicates have occurred. And run a select query on those columns.

    在现实世界中,我们倾向于从不同的来源收集数据。 有重复的记录并不少见。 解决重复问题的一种方法是首先确定重复发生在哪里。 并对这些列运行选择查询。

    EATE TABLE tb_spaceused
    (database_name       NVARCHAR(128), 
     database_size       VARCHAR(18), 
     [unallocated space] VARCHAR(18), 
     reserved            VARCHAR(18), 
     data                VARCHAR(18), 
     index_size          VARCHAR(18), 
     unused              VARCHAR(18)
    );
    INSERT INTO tb_spaceused
    EXEC sp_msforeachdb 
         @command1 = "use ? exec sp_spaceused  @oneresultset = 1";
     
    SELECT *
    FROM tb_spaceused
    order by database_name
    

    The following example uses the PARTITION BY argument to partition the query result set by all the columns of tb_spaceused table. The Row_Number (), a window function, which means it operates over an ordered set. The ORDER BY clause specified in the OVER clause orders the rows in each partition by the entire columns tb_spaceused table.

    以下示例使用PARTITION BY参数将查询结果集按tb_spaceused表的所​​有列进行分区 。 Row_Number()是一个窗口函数,这意味着它将对有序集进行操作。 OVER子句中指定的ORDER BY子句按tb_spaceused表的整个列对每个分区中的行进行排序。

    WITH CTE
         AS (SELECT *, 
                    ROW_NUMBER() OVER(PARTITION BY database_name, 
                                                   database_size, 
                                                   [unallocated space], 
                                                   reserved, 
                                                   data, 
                                                   index_size, 
                                                   unused
                    ORDER BY database_name
                            ) AS Row_Num
             FROM tb_spaceused)
         SELECT *
         FROM CTE
         WHERE Row_Num <> 1;
    

    The following example uses the PARTITION BY argument to partition the query result set by all the columns of tb_spaceused table.

    Replacing the Select statement with a Delete removes all the duplicates of the table.

    用Delete替换Select语句将删除表的所有重复项。

    WITH CTE
         AS (SELECT *, 
                    ROW_NUMBER() OVER(PARTITION BY database_name, 
                                                   database_size, 
                                                   [unallocated space], 
                                                   reserved, 
                                                   data, 
                                                   index_size, 
                                                   unused
                    ORDER BY database_name
                            ) AS Row_Num
             FROM tb_spaceused)
         --SELECT *
         --FROM CTE
         --WHERE Row_Num <> 1;
    	 DELETE FROM CTE
         WHERE Row_Num <> 1;
    

    Replacing the Select statement with a Delete removes all the duplicates of the table.

    如何使用SQL子查询删除行 (How to delete rows using SQL sub-queries)

    In the following example, the rows in one table are deleted based on data in another table. In the examples, the rows from the SalesPersonQuotaHistory table are deleted based on the SalesYTD column of the SalesPerson table.

    在以下示例中,一个表中的行基于另一表中的数据被删除。 在示例中,根据SalesPerson表的SalesYTD列删除SalesPersonQuotaHistory表中的行。

    DELETE FROM Sales.SalesPersonQuotaHistory
    WHERE BusinessEntityID IN
    (
        SELECT BusinessEntityID
        FROM Sales.SalesPerson
        WHERE SalesYTD > 4900000.00
    ); 
    GO
    

    如何使用SQL联接删除行 (How to delete rows using SQL Joins )

    In this section, we will use the SQL Delete statement to delete the data from the Adeventureworks2014 database. Deleting data, at first sight, sound trivial, but once we get into a large database design things might not be same and easy anymore.

    在本节中,我们将使用SQL Delete语句从Adeventureworks2014数据库中删除数据。 乍一看,删除数据似乎微不足道,但是一旦我们进入大型数据库设计,事情可能就不再那么简单了。

    In many cases, the tables are related via a primary and foreign key relationship. In the following example, we can see a use of joins to delete the data from the Sales.SalesPersonQuotaHistory.

    在许多情况下,这些表通过主键和外键关系进行关联。 在以下示例中,我们可以看到使用联接从Sales.SalesPersonQuotaHistory中删除数据

    DELETE sq
    FROM Sales.SalesPersonQuotaHistory sq
         INNER JOIN Sales.SalesPerson sp ON sq.BusinessEntityID = sp.BusinessEntityID
    WHERE sp.SalesYTD > 4500000.00;  
    GO
    

    如何使用链接的服务器和OpenQuery从远程表中删除行 (How to delete rows from a remote table using linked servers and OpenQuery)

    The following example uses the SQL delete statement to delete rows from a remote table using the linked server named, hqdbt01. Then query the remote table using four-part object naming convention to delete the rows from the remote table

    下面的示例使用SQL delete语句使用名为hqdbt01的链接服务器从远程表中删除行。 然后使用四部分对象命名约定查询远程表以从远程表中删除行

    DELETE
    FROM [hqdbt01].AdventureWorks2014.[HumanResources].[Shift]
    WHERE ShiftID = 2;
    

    The following example, the remote table is queried by specifying the OPENQUERY rowset function along with the delete command.

    在以下示例中,通过指定OPENQUERY行集函数以及delete命令来查询远程表。

    DELETE OPENQUERY (hqdbt01, 'SELECT *
    FROM AdventureWorks2014.HumanResources.Department  
    WHERE DepartmentID = 18');
    

    如何使用SSMS删除行 (How to delete rows using SSMS)

    Using the SQL Server Management Studio (SSMS), Graphical User Interface (GUI) to delete rows involves a manual search. In reality, it will be much easier and quicker to delete records with a SQL query.

    使用SQL Server Management Studio(SSMS),图形用户界面(GUI)删除行涉及手动搜索。 实际上,使用SQL查询删除记录将更加容易和快捷。

    Let’s go ahead and locate the table to use a SQL delete statement, in this case, table dbo.cities is selected. Now, right-click and choose Edit Top 200 rows. This option opens up a query designer window. Next, right-click the window and select Execute SQL and write a new query that will delete rows from the dbo.cities table.

    让我们继续查找表以使用SQL delete语句,在这种情况下,将选择表dbo.cities 。 现在,右键单击并选择编辑前200行 。 此选项将打开查询设计器窗口。 接下来,右键单击该窗口并选择Execute SQL并编写一个新查询,该查询将从dbo.cities表中删除行。

    How to delete rows using SSMS

    In the result pane, make sure that SELECT Statement is pulling up the correct targeted records before start deleting rows. Select the rows and right-click the rows and choose Delete to remove the rows from the table.

    在结果窗格中,在开始删除行之前,请确保SELECT语句提取正确的目标记录。 选择行并右键单击行,然后选择“ 删除”以从表中删除行。

    SQL delete - Select the rows and right-click the rows and choose Delete to remove the rows from the table.

    摘要 (Summary)

    Thus far, we’ve seen many different ways use the SQL delete statement to remove data. But, there is a list of the consideration to be followed while using the delete statement, and it as follows:

    到目前为止,我们已经看到使用SQL delete语句删除数据的许多不同方式。 但是,在使用delete语句时,有一个注意事项列表,如下所示:

    1. It is always recommended to start with a SELECT statement before you delete anything to make sure that you’re targeting the correct records. So the delete statement is used to delete rows from a table using the where clause to select only the rows to be deleted

      始终建议从SELECT语句开始,然后再删除任何内容,以确保定位的是正确的记录。 因此,delete语句用于使用where子句从表中删除行,以仅选择要删除的行
    2. Always use a unique identifier to locate the rows that you need to delete

      始终使用唯一标识符查找需要删除的行
    3. To delete all the rows in a table, always use TRUNCATE TABLE. TRUNCATE TABLE which is faster than a SQL delete statement and it uses fewer system and transaction-log resources

      要删除表中的所有行,请始终使用TRUNCATE TABLE。 TRUNCATE TABLE比SQL delete语句快,并且使用较少的系统和事务日志资源
    4. By default, DELETE statements induce an exclusive (X) lock on the table, and it holds the lock until the transaction completes

      默认情况下,DELETE语句在表上引入互斥(X)锁,并持有该锁,直到事务完成为止
    5. NOLOCK hint or read uncommitted NOLOCK提示或读取未提交的isolation level 隔离级别允许读取操作
    6. It is recommended to specify the TABLOCK hint in the delete statement. This process allows page de-allocation and associated space available for reuse by other objects in the database

      建议在delete语句中指定TABLOCK提示。 此过程允许页面解除分配以及相关的空间可用于数据库中的其他对象重用
    7. It is good practice to create a clustered index on the heap table before executing a delete statement

      优良作法是在执行删除语句之前在堆表上创建聚簇索引
    8. Although very simple and very powerful, and the result of a Delete statement is destructive. Deleted rows cannot be easily recovered

      尽管非常简单且非常强大,但Delete语句的结果却具有破坏性。 删除的行无法轻易恢复

    Note: To recover deleted rows see SQL Server disaster recovery – How to quickly recover data lost due to an Inadvertent delete operation

    注意:要恢复已删除的行,请参阅SQL Server灾难恢复–如何快速恢复由于无意删除操作而丢失的数据

    That’s all for now… Hope you enjoy reading this article on the SQL delete statement. If you have any questions, feel free to comment below.

    现在就这些了……希望您喜欢阅读有关SQL delete语句的本文。 如有任何疑问,请在下面发表评论。

    翻译自: https://www.sqlshack.com/overview-of-the-sql-delete-statement/

    sql delete语句

    展开全文
  • java http 发送 put delete post get请求

    热门讨论 2015-05-27 14:31:38
    是一个Java 发送http put、delete、 post、 get 请求的工具类。可用在与restful service 进行通讯的代码中。
  • C++的new和delete详解

    万次阅读 多人点赞 2019-06-21 15:03:54
    new和delete的内部实现 C++中如果要在堆内存中创建和销毁对象需要借助关键字new和delete来完成。比如下面的代码 class CA { public: CA():m_a(0){} CA(int a):m_a(a){} virtual void foo(){ cout<<m_a...

    new和delete的内部实现

    C++中如果要在堆内存中创建和销毁对象需要借助关键字new和delete来完成。比如下面的代码

    class CA
    {
        public:
           CA():m_a(0){}
           CA(int a):m_a(a){}
    
           virtual void foo(){ cout<<m_a<<endl;}
           int m_a;
    };
    
    void main()
    {
           CA *p1 = new CA;
           CA *p2 = new CA(10);
           CA *p3 = new CA[20];
    
           delete p1;
           delete p2;
           delete[] p3;
    }
    
    

    new和delete既是C++中的关键字也是一种特殊的运算符。

       void* operator new(size_t size);
       void* operator new[](size_t size);
       void  operator delete(void *p);
       void  operator delete[](void *p);
    

    new和delete不仅承载着内存分配的功能还承载着对象构造函数的调用功能,因此上面的对象创建代码其实在编译时会转化为如下的实现:

          CA *p1 = operator new(sizeof(CA));  //分配堆内存
          CA::CA(p1);   //调用构造函数
    
          CA *p2 = operator new(sizeof(CA));  //分配堆内存
          CA::CA(p2, 10);   //调用构造函数
         
          CA *p3 = operator new[](20 * sizeof(CA));
          CA *pt = p3;
          for (int i = 0; i < 20; i++)
         {
             CA::CA(pt);
             pt += 1;
         }
    
         CA::~CA(p1);
         operator delete(p1);
         
         CA::~CA(p2);
         operator delete(p2);
    
         CA *pt = p3;
         for (int i = 0; i < 20; i++)
         {
              CA::~CA(pt);
              pt += 1;
         }
         operator delete[](p3);
    
    

    看到上面的代码也许你会感到疑惑,怎么在编译时怎么会在源代码的基础上插入这么多的代码。这也是很多C程序员吐槽C++语言的原因:C++编译器会偷偷插入很多未知的代码或者对源代码进行修改和处理,而这些插入和修改动作对于程序员来说是完全不可知的!
    言归正传,我们还能从上面的代码中看出new和delete操作其实是分别进行了2步操作:1.内存的分配,2.构造函数的调用;3.析构函数的调用,4.内存的销毁。所以当对象是从堆内存分配时,构造函数执前内存就已经完成分配,同样当析构函数执行完成后内存才会被销毁。
    这里面一个有意思的问题就是当我们分配或者销毁的是数组对象时,系统又是如何知道应该调用多少次构造函数以及调用多少次析构函数的呢?答案就是在内存分配里面。当我们调用operator new[]来分配数组对象时,编译器时系统内部会增加4或者8字节的分配空间用来保存所分配的数组对象的数量。当对数组对象调用构造和析构函数时就可以根据这个数量值来进行循环处理了。因此上面对数组对象的分配和销毁的真实代码其实是按如下方式处理的:

         //  CA *p3 = new CA[20]; 这句代码在编译时其实会转化为如下的代码片段
         unsigned long *p = operator new[](20 * sizeof(CA) + sizeof(unsigned long));  //64位系统多分配8字节
         *p = 20;   //这里保存分配的对象的数量。
         CA *p3 = (CA*)(p + 1);
         CA *pt = p3;
         for (int i = 0; i < *p; i++)
         {
             CA::CA(pt);
             pt += 1;
         }
    
    
        // delete[] p3;   这句代码在编译时其实会转化为如下的代码片段
         unsigned long *p =  ((unsigned long*)p3)  - 1;
         CA *pt = p3;
         for (int i = 0; i < *p; i++)
         {
              CA::~CA(pt);
              pt += 1;
          }
          operator delete[](p);
    

    可见C++中为我们隐藏了多少细节啊! 这里需要注意的是分配数组内存时会增加额外的存储空间来保存数量的情况只会发生在对类进行内存分配的情况,而对于基础类型进行内存分配则不会增加额外的空间来保存数量,比如下面的代码:

        int *p = new int[30];
    

    之所以会有这种差异的原因是因为类对象的构建和销毁时存在着构造函数和析构函数的调用,因此必须要保存数量来对每个元素进行函数调用的遍历处理,而普通类型则没有这个步骤。这也是编译器对各种类型数据的构建和销毁的一个优化处理。

    既然new和delete操作默认是从堆中进行内存分配,而且new和delete又是一个普通的运算符函数,那么他内部是如何实现呢?其实也很简单。我们知道C语言中堆内存分配和销毁的函数是malloc/free。因此C++中对系统默认的new和delete运算符函数就可以按如下的方法实现:

    void * operator new(size_t size)
    {
         return malloc(size);
    } 
    
    void * operator new[](size_t size)
    {
         return malloc(size);
    }
    
    void operator delete(void *p)
    {
         free(p);
    }
    
    void operator delete[](void *p)
    {
        free(p);
    }
    

    这里需要注意的是你在代码里面使用new关键字和使用operator new操作符所产生的效果是不一样的。如果你在代码里面使用的是new关键字那么系统内部除了会调用operator new操作符来分配内存还会调用构造函数,而如果你直接使用operator new时则只会进行内存分配而不会执行任何构造就比如下面的代码:

       CA *p1 = new CA;   //这里会分配内存和执行构造函数
    
       CA *p2 = operator new(sizeof(CA));   //这里只是执行了普通的堆内存分配而不会调用构造函数
    

    上述的伪代码都是在运行时通过查看汇编语言而得出的结论,我是在XCODE编译器上查看运行的结果,有可能不同的编译器会有一些实现的差异,但是不管如何要想真实的了解内部实现原理还是要懂一些汇编的知识为最好。

    placement技术

    系统默认的new关键字除了分配堆内存外还进行构造函数的调用。而实际中我们可能有一些已经预先分配好的内存区域,我们想在这些已经分配好的内存中来构建一个对象。还有一种情况是不希望进行频繁的堆内存分配和释放而只是对同一块内存进行重复的对象构建和销毁。就如下面的代码:

    
    char buf1[100];
    CA *p1 = (CA*)buf1;
    CA::CA(p1);
    p1->foo();
    p1->m_a = 10;
    
    
    char *buf2 = new char[sizeof(CA)];
    CA *p2 = (CA*)buf2;
    CA::CA(p2);
    p2->foo();
    p2->m_a = 20;
    
    
    p1->~CA();
    p2->~CA();
    
    delete[] buf2;
    
    

    可以看出代码中buf1是栈内存而buf2是堆内存,这两块内存区域都是已经分配好了的内存,现在我们想把这些内存来当做CA类的对象来使用,因此我们需要对内存调用类的构造函数CA::CA()才可以,构造函数的内部实现会为内存区域填充虚表指针,这样对象才可以调用诸如foo虚函数。但是这样写代码不够优雅,那么有没有比较优雅的方法来实现在一块已经存在的内存上来构建对象呢? 答案就是 placement技术。 C++中的仍然是使用new和delete来实现这种技术。new和delete除了实现默认的操作符外还重载实现了如下的操作符函数:

    void* operator new(size_t  size, void *p)
    {
       return p;
    }
    
    void* operator new[](size_t size, void *p)
    {
       return p;
    }
    
    void operator delete(void *p1, void *p2)
    {
       // do nothing..
    }
    
    void operator delete[](void *p1, void *p2)
    {
       // do nothing..
    }
    
    

    我们称这四个运算符为 placement new 和 placement delete 。通过这几个运算符我们就可以优雅的实现上述的功能:

    char buf1[100];
    CA *p1 = new(buf1) CA(10)   //调用 operator new(size_t, void*)
    p1->foo();
    
    
    char *buf2 = new char[sizeof(CA)];
    CA *p2 = new(buf2) CA(20);     //调用 operator new(size_t, void*)
    p2->foo();
    
    
    p1->~CA();
    operator delete(p1, buf1);  //调用 operator delete(void*, void*)
    
    p2->~CA();
    operator delete(p2, buf2);  //调用 operator delete(void*, void*)
    
    delete[] buf2;
    
    

    上面的例子里面发现通过placement new可以很优雅的在现有的内存中构建对象,而析构时不能直接调用delete p1, delete p2来销毁对象,必须人为的调用析构函数以及placement delete 函数。并且从上面的placement delete的实现来看里面并没有任何代码,既然如此为什么还要定义一个placement delete呢? 答案就是C++中的规定对new和delete的运算符重载必须是要成对实现的。而且前面曾经说过对delete的使用如果带了operator前缀时就只是一个普通的函数调用。因此为了完成析构以及和new操作符的匹配,就必须要人为的调用对象的析构函数以及placement delete函数。
    除了上面举的例子外placement技术的使用还可以减少内存的频繁分配以及提升系统的性能。

    void main()
    {
          for (int i = 0; i < 10000; i++)
          {
               CA *p = new CA(i);
               p->foo();
               delete p;
          }
    }
    
    

    例子里面循环10000次,每次循环都创建一个堆内存对象,然后调用虚函数foo后再进行销毁。最终的结果是程序运行时会进行10000次的频繁的堆内存分配和销毁。很明显这是有可能会影响系统性能的而且还有可能发生堆内存分配失败的情况。而如果我们借助placement 技术就可以很简单的解决这些问题。

    
    void main()
    {
          char *buf = new[](sizeof(CA));
          for (int i = 0; i < 10000; i++)
          {
                CA *p = new(buf) CA(i);
                p->foo();
                p->~CA();
                operator delete(p, buf);
          }
          delete[] buf;
    }
    

    上面的例子里面只进行了一次堆内存分配,在循环里面都是借助已经存在的内存来构建对象,不会再分配内存了。这样对内存的重复利用就使得程序的性能得到非常大的提升。

    new和delete运算符重载

    发现一个很有意思的事情就是越高级的语言就越会将一些系统底层的东西进行封装并形成一个语言级别的关键字来使用。比如C++中的new和delete是用于构建和释放堆内存对象的关键字,又比如go语言中chan关键字是用于进行同步或者异步的队列数据传输通道。
    C++语言内置默认实现了一套全局new和delete的运算符函数以及placement new/delete运算符函数。不管是类还是内置类型都可以通过new/delete来进行堆内存对象的分配和释放的。对于一个类来说,当我们使用new来进行构建对象时,首先会检查这个类是否重载了new运算符,如果这个类重载了new运算符那么就会调用类提供的new运算符来进行内存分配,而如果没有提供new运算符时就使用系统提供的全局new运算符来进行内存分配。内置类型则总是使用系统提供的全局new运算符来进行内存的分配。对象的内存销毁流程也是和分配一致的。
    new和delete运算符既支持全局的重载又支持类级别的函数重载。下面是这种运算符的定义的格式:

    //全局运算符定义格式
    void * operator new(size_t size [, param1, param2,....]);
    void operator delete(void *p [, param1, param2, ...]);
    
    //类内运算符定义格式
    class CA
    {
      void * operator new(size_t size [, param1, param2,....]);
      void operator delete(void *p [, param1, param2, ...]);
    };
    
    

    对于new/delete运算符重载我们总有如何下规则:

    • new和delete运算符重载必须成对出现
    • new运算符的第一个参数必须是size_t类型的,也就是指定分配内存的size尺寸;delete运算符的第一个参数必须是要销毁释放的内存对象。其他参数可以任意定义。
    • 系统默认实现了new/delete、new[]/delete[]、 placement new / delete 6个运算符函数。它们都有特定的意义。
    • 你可以重写默认实现的全局运算符,比如你想对内存的分配策略进行自定义管理或者你想监测堆内存的分配情况或者你想做堆内存的内存泄露监控等。但是你重写的全局运算符一定要满足默认的规则定义。
    • 如果你想对某个类的堆内存分配的对象做特殊处理,那么你可以重载这个类的new/delete运算符。当重载这两个运算符时虽然没有带static属性,但是不管如何对类的new/delete运算符的重载总是被认为是静态成员函数。
    • 当delete运算符的参数>=2个时,就需要自己负责对象析构函数的调用,并且以运算符函数的形式来调用delete运算符。

    一般情况下你不需要对new/delete运算符进行重载,除非你的整个应用或者某个类有特殊的需求时才会如此。下面的例子你可以看到我的各种运算符的重载方法以及使用方法:

    //CA.h
    
    class CA
    {
    public:
        //类成员函数
        void * operator new(size_t size);
        void * operator new[](size_t size);
        void * operator new(size_t size, void *p);
        void * operator new(size_t size, int a, int b);
        
        void operator delete(void *p);
        void operator delete[](void *p);
        void operator delete(void *p, void *p1);
        void operator delete(void *p, int a, int b);
    };
    
    class CB
    {
    public:
        CB(){}
    };
    
    
    //全局运算符函数,请谨慎重写覆盖全局运算符函数。
    void * operator new(size_t size);
    void * operator new[](size_t size);
    void * operator new(size_t size, void *p) noexcept;
    void * operator new(size_t size, int a, int b);
    
    void operator delete(void *p);
    void operator delete[](void *p);
    void operator delete(void *p, void *p1);
    void operator delete(void *p, int a, int b);
    
    .......................................................
    //CA.cpp
    
    
    void * CA::operator new(size_t size)
    {
        return malloc(size);
    }
    
    void * CA::operator new[](size_t size)
    {
        return malloc(size);
    }
    
    void * CA::operator new(size_t size, void *p)
    {
        return p;
    }
    
    void* CA::operator new(size_t size, int a, int b)
    {
        return malloc(size);
    }
    
    void CA::operator delete(void *p)
    {
        free(p);
    }
    
    void CA::operator delete[](void *p)
    {
        free(p);
    }
    
    void CA::operator delete(void *p, void *p1)
    {
        
    }
    
    void CA::operator delete(void *p, int a, int b)
    {
        free(p);
    }
    
    
    void * operator new(size_t size)
    {
        return  malloc(size);
    }
    
    void * operator new[](size_t size)
    {
        return malloc(size);
    }
    
    void * operator new(size_t size, void *p) noexcept
    {
        return p;
    }
    
    void* operator new(size_t size, int a, int b)
    {
        return malloc(size);
    }
    
    void operator delete(void *p)
    {
        free(p);
    }
    
    void operator delete[](void *p)
    {
        free(p);
    }
    
    void operator delete(void *p, void *p1)
    {
        
    }
    
    void operator delete(void *p, int a, int b)
    {
        free(p);
    }
    
    ..................................
    //main.cpp
    
    int main(int argc, const char * argv[]) {
        
        char buf[100];
    
        CA *a1 = new CA();   //调用void * CA::operator new(size_t size)
        
        CA *a2 = new CA[10];  //调用void * CA::operator new[](size_t size)
        
        CA *a3 = new(buf)CA();  //调用void * CA::operator new(size_t size, void *p)
        
        CA *a4 = new(10, 20)CA();  //调用void* CA::operator new(size_t size, int a, int b)
        
        
        delete a1;  //调用void CA::operator delete(void *p)
        
        delete[] a2;  //调用void CA::operator delete[](void *p)
        
        //a3用的是placement new的方式分配,因此需要自己调用对象的析构函数。
        a3->~CA();
        CA::operator delete(a3, buf);  //调用void CA::operator delete(void *p, void *p1),记得要带上类命名空间。
    
        //a4的运算符参数大于等于2个所以需要自己调用对象的析构函数。
        a4->~CA();
        CA::operator delete(a4, 10, 20); //调用void CA::operator delete(void *p, int a, int b)
        
        //CB类没有重载运算符,因此使用的是全局重载的运算符。
        
        CB *b1 = new CB();  //调用void * operator new(size_t size)
     
        
        CB *b2 = new CB[10]; //调用void * operator new[](size_t size)
        
        //这里你可以看到同一块内存可以用来构建CA类的对象也可以用来构建CB类的对象
        CB *b3 = new(buf)CB();  //调用void * operator new(size_t size, void *p)
        
        CB *b4 = new(10, 20)CB(); //调用void* operator new(size_t size, int a, int b)
        
    
        delete b1;  //调用void operator delete(void *p)
    
        
        delete[] b2;   //调用void operator delete[](void *p)
        
        
        //b3用的是placement new的方式分配,因此需要自己调用对象的析构函数。
        b3->~CB();
        ::operator delete(b3, buf);  //调用void operator delete(void *p, void *p1)
        
        //b4的运算符参数大于等于2个所以需要自己调用对象的析构函数。
        b4->~CB();
        ::operator delete(b4, 10, 20);  //调用void operator delete(void *p, int a, int b)
       
       return 0;
    } 
    

    我是在XCODE上测试上面的代码的,因为重写了全局的new/delete运算符,并且内部是通过malloc来实现堆内存分配的, malloc函数申明了不能返回NULL的返回结果检测:
    void *malloc(size_t __size) __result_use_check __alloc_size(1);
    因此有可能你在测试时会发生崩溃的问题。如果出现这个问题你可以尝试着注释掉对全局new/delete重写的代码,再运行查看结果。 可见如果你尝试着覆盖重写全局的new/delete时是有可能产生风险的。

    对象的自动删除技术

    一般来说系统对new/delete的默认实现就能满足我们的需求,我们不需要再去重载这两个运算符。那为什么C++还提供对这两个运算符的重载支持呢?答案还是在运算符本身具有的缺陷所致。我们知道用new关键字来创建堆内存对象是分为了2步:1.是堆内存分配,2.是对象构造函数的调用。而这两步中的任何一步都有可能会产生异常。如果说是在第一步出现了问题导致内存分配失败则不会调用构造函数,这是没有问题的。如果说是在第二步构造函数执行过程中出现了异常而导致无法正常构造完成,那么就应该要将第一步中所分配的堆内存进行销毁。C++中规定如果一个对象无法完全构造那么这个对象将是一个无效对象,也不会调用析构函数。为了保证对象的完整性,当通过new分配的堆内存对象在构造函数执行过程中出现异常时就会停止构造函数的执行并且自动调用对应的delete运算符来对已经分配的堆内存执行销毁处理,这就是所谓的对象的自动删除技术。正是因为有了对象的自动删除技术才能解决对象构造不完整时会造成内存泄露的问题。

    当对象构造过程中抛出异常时,C++的异常处理机制会在特定的地方插入代码来实现对对象的delete运算符的调用,如果想要具体了解情况请参考C++对异常处理实现的相关知识点。

    全局delete运算符函数所支持的对象的自动删除技术虽然能解决对象本身的内存泄露问题,但是却不能解决对象构造函数内部的数据成员的内存分配泄露问题,我们来看下面的代码:

    class CA
    {
      public:
        CA()
        {
              m_pa  = new int;
              throw 1;
        }
    
      ~CA()
       {
             delete m_pa;
             m_pa = NULL;
       }
    
     private:
          int *m_pa;
    };
    
    void main()
    {
         try
         {
               CA *p = new CA();
               delete p;  //这句代码永远不会执行
         }
         catch(int)
        {
              cout << "oops!" << endl;
        }
    }
    

    上面的代码中可以看到类CA中的对象在构造函数内部抛出了异常,虽然系统会对p对象执行自动删除技术来销毁分配好的内存,但是对于其内部的数据成员m_pa来说,因为构造不完整就不会调用析构函数来销毁分配的堆内存,这样就导致了m_pa这块内存出现了泄露。怎么解决这类问题呢? 答案你是否想到了? 那就是重载CA类的new/delete运算符。我们来看通过对CA重载运算符解决问题的代码:

    class CA
    {
    public:
        CA(){
            m_pa = new int;
            throw 1;
        }
        //因为对象构造未完成所以析构函数永远不会被调用
        ~CA()
        {
            delete m_pa;
            m_pa = NULL;
        }
        
        void * operator new(size_t size)
        {
            return malloc(size);
        }
        //重载delete运算符,把已经分配的内存销毁掉。
        void operator delete(void *p)
        {
            CA *pb = (CA*)p;
            if (pb->m_pa != NULL)
                delete pb->m_pa;
            
            free(p);
        }
        
    private:
        int *m_pa;
    };
    

    因为C++对自动删除技术的支持,当CA对象在构造过程中发生异常时,我们就可以通过重载delete运算符来解决那些在构造函数中分配的数据成员内存但又不会调用析构函数来销毁的数据成员的内存问题。这我想就是为什么C++中要支持对new/delete运算符在类中重载的原因吧。


     

    展开全文
  • elasticsearch 基础 —— Delete By Query API

    千次阅读 2018-09-14 14:36:36
    Delete By Query API _delete_by_query 的简单用法,就是在查询匹配到的每个文档上执行删除。例如: POST twitter/_delete_by_query { "query": { ① "match": { "message": &...

    Delete By Query API

    _delete_by_query 的简单用法,就是在查询匹配到的每个文档上执行删除。例如:

    POST twitter/_delete_by_query
    {
      "query": { ①
        "match": {
          "message": "some message"
        }
      }
    }

    ①:查询必须是有效的键值对,query是键,这和Search API是同样的方式。在search apiq参数和上面效果是一样的。

    返回如下内容:

    {
      "took" : 147,
      "timed_out": false,
      "deleted": 119,
      "batches": 1,
      "version_conflicts": 0,
      "noops": 0,
      "retries": {
        "bulk": 0,
        "search": 0
      },
      "throttled_millis": 0,
      "requests_per_second": -1.0,
      "throttled_until_millis": 0,
      "total": 119,
      "failures" : [ ]
    }

     _delete_by_query在索引启动时获取索引的快照,并使用internal版本控制删除它找到的内容。这意味着如果文档在拍摄快照的时间和处理删除请求之间发生更改,则会出现版本冲突。当版本匹配时,文档将被删除。

    由于internal版本控制不支持将值0作为有效版本号,因此无法使用版本等于0的文档删除, _delete_by_query并且将使请求失败。

    _delete_by_query执行期间,顺序执行多个搜索请求以便找到要删除的所有匹配文档。每次找到一批文档时,都会执行相应的批量请求以删除所有这些文档。如果搜索或批量请求被拒绝,则_delete_by_query依赖于默认策略来重试被拒绝的请求(最多10次,指数后退)。达到最大重试次数限制会导致_delete_by_query 中止,并failures在响应中返回所有失败。已执行的删除仍然有效。换句话说,该过程不会回滚,只会中止。当第一个失败导致中止时,失败的批量请求返回的所有失败都将返回到failures元件; 因此,可能存在相当多的失败实体。

    如果您想计算版本冲突而不是让它们中止,那么请conflicts=proceed在URL或"conflicts": "proceed"请求正文中设置。

    下面仅仅只是删除索引twitter中类型tweet的所有数据:

    POST twitter/tweet/_delete_by_query?conflicts=proceed
    {
      "query": {
        "match_all": {}
      }
    }

    一次删除多个索引中的多个类型中的数据,也是可以的。例如:

    POST twitter,blog/tweet,post/_delete_by_query
    {
      "query": {
        "match_all": {}
      }
    }

    如果你提供了routing,接着这个路由会被复制给scroll query,根据匹配到的路由值,来决定哪个分片来处理:

    POST twitter/_delete_by_query?routing=1
    {
      "query": {
        "range" : {
            "age" : {
               "gte" : 10
            }
        }
      }
    }

    默认情况下,_delete_by_query自上而下批量1000条数据,你也可以在URL中使用参数scroll_size

    POST twitter/_delete_by_query?scroll_size=5000
    {
      "query": {
        "term": {
          "user": "kimchy"
        }
      }
    }

    URL参数

    除了标准的参数,如pretty,删除通过查询API也支持refreshwait_for_completionwait_for_active_shardstimeout 和scroll

    发送refresh请求将在请求完成后刷新查询删除中涉及的所有分片。这与Delete API的refresh 参数不同,后者仅导致接收删除请求的分片被刷新。

    如果请求包含,wait_for_completion=false则Elasticsearch将执行一些预检检查,启动请求,然后返回task 可与Tasks API 一起使用以取消或获取任务状态的请求。Elasticsearch还将创建此任务的记录作为文档.tasks/task/${taskId}。这是你的保留或删除你认为合适。完成后,删除它,以便Elasticsearch可以回收它使用的空间。

    wait_for_active_shards控制在继续请求之前必须激活碎片的副本数量。详情请见此处 。timeout控制每个写入请求等待不可用分片变为可用的时间。两者都完全适用于 Bulk API中的工作方式。由于_delete_by_query采用滚动搜索,你还可以指定scroll参数来控制多长时间保持“搜索上下文”活着,例如?scroll=10m,默认情况下它是5分钟。

    requests_per_second可以被设置为任何正十进制数(1.46, 1000等)和节流速率_delete_by_query通过填充每个批次由一等待时间发出的删除操作的批次。可以通过设置requests_per_second为禁用限制-1

    通过在批处理之间等待来完成限制,以便在_delete_by_query内部使用的滚动 可以被赋予考虑填充的超时。填充时间是批量大小除以requests_per_second写入所花费的时间之间的差异。默认情况下,批处理大小为1000,因此如果requests_per_second设置为500

    target_time = 1000 / 500 per second = 2 seconds
    wait_time = target_time - write_time = 2 seconds - .5 seconds = 1.5 seconds

    由于批处理是作为单个_bulk请求发出的,因此大批量数据将导致Elasticsearch创建许多请求,然后等待一段时间再开始下一组。这是“突发”而不是“平滑”。默认是-1

    Response body

    {
      "took" : 147,
      "timed_out": false,
      "total": 119,
      "deleted": 119,
      "batches": 1,
      "version_conflicts": 0,
      "noops": 0,
      "retries": {
        "bulk": 0,
        "search": 0
      },
      "throttled_millis": 0,
      "requests_per_second": -1.0,
      "throttled_until_millis": 0,
      "failures" : [ ]
    }

    took

    整个操作从开始到结束的毫秒数。

    timed_out

    true如果在通过查询执行删除期间执行的任何请求超时 ,则将此标志设置为。

    total

    已成功处理的文档数。

    deleted

    已成功删除的文档数。

    batches

    通过查询删除拉回的滚动响应数。

    version_conflicts

    按查询删除的版本冲突数。

    noops

    对于按查询删除,此字段始终等于零。它只存在,以便通过查询删除,按查询更新和reindex API返回具有相同结构的响应。

    retries

    通过查询删除尝试的重试次数。bulk是重试的批量操作search的数量,是重试的搜索操作的数量。

    throttled_millis

    请求睡眠符合的毫秒数requests_per_second

    requests_per_second

    在通过查询删除期间有效执行的每秒请求数。

    throttled_until_millis

    在按查询响应删除时,此字段应始终等于零。它只在使用Task API时有意义,它指示下一次(自纪元以来的毫秒数),为了符合,将再次执行受限制的请求requests_per_second

    failures

    如果在此过程中存在任何不可恢复的错误,则会出现故障数组。如果这是非空的,那么请求因为那些失败而中止。逐个查询是使用批处理实现的,任何故障都会导致整个进程中止,但当前批处理中的所有故障都会被收集到数组中。您可以使用该conflicts选项来防止reindex在版本冲突中中止。

    Works with the Task API

    你可以使用Task API来获取任何一个正在运行的delete-by-query请求的状态。

    GET _tasks?detailed=true&actions=*/delete/byquery
    

    返回如下内容:

    {
      "nodes" : {
        "r1A2WoRbTwKZ516z6NEs5A" : {
          "name" : "r1A2WoR",
          "transport_address" : "127.0.0.1:9300",
          "host" : "127.0.0.1",
          "ip" : "127.0.0.1:9300",
          "attributes" : {
            "testattr" : "test",
            "portsfile" : "true"
          },
          "tasks" : {
            "r1A2WoRbTwKZ516z6NEs5A:36619" : {
              "node" : "r1A2WoRbTwKZ516z6NEs5A",
              "id" : 36619,
              "type" : "transport",
              "action" : "indices:data/write/delete/byquery",
              "status" : {    ①
                "total" : 6154,
                "updated" : 0,
                "created" : 0,
                "deleted" : 3500,
                "batches" : 36,
                "version_conflicts" : 0,
                "noops" : 0,
                "retries": 0,
                "throttled_millis": 0
              },
              "description" : ""
            }
          }
        }
      }
    }

    ①这个对象包含实际的状态。响应体是json格式,其中total字段是非常重要的。total表示期望执行reindex操作的数量。你可以通过加入的updatedcreateddeleted字段来预估进度。但它们之和等于total字段时,请求将结束。

    使用task id可以直接查找此task

    GET /_tasks/taskId:1

    这个api的优点是它整合了wait_for_completion=false来透明的返回已完成任务的状态。如果此任务完成并且设置为wait_for_completion=false,那么其将返回results或者error字段。这个特性的代价就是当设置wait_for_completion=false时,会在.tasks/task/${taskId}中创建一个文档。当然你也可以删除这个文档。

    Works with the Cancel Task API

    任何一个Delete By Query都可以使用Task Cancel API来取消掉:

    POST _tasks/task_id:1/_cancel

    可以使用上面的task api来找到task_id; 
    取消应该尽快发生,但是也可能需要几秒钟,上面的task 状态 api将会进行列出task直到它被唤醒并取消自己。

    Rethrottling

    requests_per_second的值可以在使用_rethrottle参数的正在运行的delete by queryapi上进行更改:

    POST _delete_by_query/task_id:1/_rethrottle?requests_per_second=-1

    使用上面的tasks API来查找task_id

    就像在_delete_by_query中设置一样,requests_per_second可以设置-1来禁止这种限制或者任何一个10进制数字,像1.7或者12来限制到这种级别。加速查询的Rethrottling会立即生效,但是缓慢查询的Rethrottling将会在完成当前批处理后生效。这是为了防止scroll timeouts

    Manually slicing

    Delete-by-query支持Sliced Scroll,其可以使你相对容易的手动并行化进程:

    POST twitter/_delete_by_query
    {
      "slice": {
        "id": 0,
        "max": 2
      },
      "query": {
        "range": {
          "likes": {
            "lt": 10
          }
        }
      }
    }
    POST twitter/_delete_by_query
    {
      "slice": {
        "id": 1,
        "max": 2
      },
      "query": {
        "range": {
          "likes": {
            "lt": 10
          }
        }
      }
    }

    你可以通过以下方式进行验证:

    GET _refresh
    POST twitter/_search?size=0&filter_path=hits.total
    {
      "query": {
        "range": {
          "likes": {
            "lt": 10
          }
        }
      }
    }

    像下面这样只有一个total是合理的:

    {
      "hits": {
        "total": 0
      }
    }

    Automatic slicing

    你也可以使用Sliced Scrolldelete-by-query api自动并行化,以在_uid上切片:

    POST twitter/_delete_by_query?refresh&slices=5
    {
      "query": {
        "range": {
          "likes": {
            "lt": 10
          }
        }
      }
    }

    你可以通过以下来验证:

    POST twitter/_search?size=0&filter_path=hits.total
    {
      "query": {
        "range": {
          "likes": {
            "lt": 10
          }
        }
      }
    }

    像下面的total是一个合理的结果:

    {
      "hits": {
        "total": 0
      }
    }

    添加slices_delete_by_query将会自动执行上面部分中使用手动处理的部分,创建子请求这意味着有些怪事:

    1. 你可以在Tasks APIs中看到这些请求。这些子请求是使用了slices请求任务的子任务。
    2. 为此请求(使用了slices)获取任务状态仅仅包含已完成切片的状态。
    3. 这些子请求都是独立寻址的,例如:取消和rethrottling.
    4. Rethrottling the request with slices will rethrottle the unfinished sub-request proportionally.
    5. 取消slices请求将会取消每个子请求。
    6. 由于slices的性质,每个子请求并不会得到完全均匀的文档结果。所有的文档都将要处理,但是有些slices(切片)会大些,有些会小些。希望大的slices(切片)有更均匀的分配。
    7. slices请求中像requests_per_secondsize参数,按比例分配给每个子请求。结合上面的关于分配的不均匀性,你应该得出结论:在包含slices_delete_by_query请求中使用size参数可能不会得到正确大小的文档结果。
    8. 每个子请求都会获得一个略微不同的源索引快照,尽管这些请求都是大致相同的时间。

    Picking the number of slices

    这里我们有些关于slices数量的建议(如果是手动并行的话,那么在slice api就是max参数):

    1. 不要使用大数字。比如500,将会创建相当大规模的CPU震荡。 
      这里说明下震荡(thrashing)的意思: 
      cpu大部分时间都在进行换页,而真正工作时间却很短的现象称之为thrashing (震荡)
    2. 从查询性能角度来看,在源索引中使用多个分片是更高效的。
    3. 从查询性能角度来看,在源索引中使用和分片相同的数量是更高效的。
    4. 索引性能应该在可利用slices之间进行线性扩展。
    5. 索引(插入)或查询性能是否占主导地位取决于诸多因素,比如:重新索引文档和集群进行重新索引。

     

     

     

     

    展开全文
  • delete后加 limit是个好习惯么

    万次阅读 多人点赞 2020-07-22 18:12:32
    在业务场景要求高的数据库中,对于单条删除和更新操作,在delete和update后面加limit 1绝对是个好习惯。比如,在删除执行中,第一条就命中了删除行,如果SQL中有limit 1;这时就return了,否则还会执行完全表扫描才...
  • deletedelete[]真正区别

    千次阅读 2019-07-19 23:11:55
    delete 释放new分配的单个对象指针指向的内存 delete[] 释放new分配的对象数组指针指向的内存 那么,按照教科书的理解,我们看下下面的代码: int *a = new int[10]; delete a; //方式1 delete [] a; //方式2 肯定...
  • C++中重载new和delete的使用

    千次阅读 2018-01-06 21:46:12
    C++中重载new和delete的使用
  • kafka日志清理策略,compact和delete

    万次阅读 多人点赞 2020-05-31 11:28:07
    日志清理delete策略3.1 delete 相关配置3.2 简单总结4. 日志清理compact策略4.1 日志compact的使用场景4.2 compact的工作模式4.3 tombstone 消息4.4 低流量topic的注意事项4.5 简单总结compact的配置5. kafka创建...
  • C++ new和delete的原理分析

    千次阅读 2017-08-28 13:55:33
    前言Effective C++ rule 16规则,让我重新认识了delete与new在处理数组时候的方式。new 有两种形式的new,一种是生成一个对象的operator New,另一个是用于数组的operator new []。同时 operator delete也分普通版本的...
  • Axios.delete 两种传参方式

    千次阅读 2020-07-23 11:31:15
    Axios中文网特意说明data 传参方式只适用于POST,PATCH 和PUT,所以一直以为delete 传参也只能用params 传参,结果github API 文档上说的是Only applicable for request methods ‘PUT’, ‘POST’, 'DELETE , and ...
  • delete用法解析

    千次阅读 2020-12-14 18:59:32
    使用delete语句一次只能删除整行记录,不能删除某个字段。 与insert和update一样,删除一个表中的记录可能会导致与其他表的引用完整性问题,当对数据库进行修改时一定要记着这一影响。 delete只会删除记录,不会删除...
  • mysql中drop、truncate和delete的区别

    千次阅读 多人点赞 2020-06-27 07:49:53
    (1)DELETE语句执行删除的过程是每次从表中删除一行,并且同时将该行的删除操作作为事务记录在日志中保存以便进行进行回滚操作。 TRUNCATETABLE则一次性地从表中删除所有的数据并不把单独的删除操作记录记入日志...
  • delete、truncate、drop的区别有哪些,该如何选择

    万次阅读 多人点赞 2020-07-05 21:44:37
    一、从执行速度上来说 drop > truncate >> DELETE 二、从原理上讲 1、DELETE DELETE from TABLE_NAME where xxx 1、DELETE属于数据库DML操作语言,只删除数据不删除表的结构,会走事务,执行时会触发trigger;...
  • java积累---HttpDelete请求方式传递参数

    万次阅读 2019-04-30 16:27:03
    public static final String METHOD_NAME = "DELETE"; public String getMethod() { return METHOD_NAME; } public HttpDeleteWithBody(final String uri) { super(); setURI(URI.create(uri)); } ...
  • 释放对象数组:deletedelete[]

    千次阅读 2018-05-28 21:33:22
     delete parray; delete [] parray; 方括号的存在会使编译器获取数组大小(size)然后析构函数再被依次应用在每个元素上,一共size次。否则,只有一个元素被析构。 无论哪种情况,分配的全部空间被...
  • new/delete 详解

    万次阅读 多人点赞 2016-05-18 14:31:12
    new 和 delete 是 C++ 用于管理 堆内存</font> 的两个运算符,对应于C语言中的 malloc 和 free,但是malloc和free是函数,new 和 delete 是运算符。
  • SQL DELETE 语句的用法

    千次阅读 2020-07-06 09:35:44
    DELETE 语句用于删除表中的行。 语法 DELETE FROM 表名称 WHERE 列名称 = 值 例表 LastName FirstName Address City Gates Bill Xuanwumen 10 Beijing Wilson Fred Zhongshan 23 ...
  • delta 增量数据文件是否需要拆分为 insert 和 delete 两部分 delete 文件的格式规范如何设计,兼顾数据摄取的吞吐量和查询效率 实现 MOR 后,minor compaction 和 major compaction 是如何设计的 在Iceberg 中 ...
  • 一般来说,Web服务器默认的只支持Post和Get这两种“只读”的请求方法。但是随着Ajax XMLHttpRequest 和 REST风格应用的深入,我们发现Http 1.1协议还支持如下... •OPTIONS •HEAD •DELETE •PUT •TRACE •CONNECT
  • C++中的deletedelete[ ]的区别

    万次阅读 多人点赞 2018-07-04 23:24:00
    以前看书的时候,书上说使用new申请的内存,释放时用delete,使用new [ ]申请的内存释放时要用delete [ ]才行,这两个一定要记住,申请时用了方括号,则释放时也要加上方括号,否则就会出错。但是并没有解释为什么...
  • DELETE 语句

    千次阅读 2020-09-30 11:46:59
    SQL DELETE作用 DELETE 语句用于删除表中的记录。 SQL DELETE 语法 DELETE FROMtable_name WHEREsome_column=some_value; 请注意 SQL DELETE 语句中的 WHERE 子句! WHERE 子句规定哪条记录或者哪些...
  • Vue.delete()

    千次阅读 2020-10-14 21:10:19
    官方文档 Vue.delete 和Vue.set()一起总结一下吧 我们平常使用vue进行开发时,会遇到vue生成实例之后,再次给数据赋值的时候,数据不会更新到视图上的情况,vue文档上说明实例创建之后添加新的属性到实例上,它不会...
  • deletedelete []的真正区别

    千次阅读 2019-01-19 23:40:12
    delete 释放new分配的单个对象指针指向的内存 delete[] 释放new分配的对象数组指针指向的内存 那么,按照教科书的理解,我们看下下面的代码: int *a = new int[10]; delete a; //方式1 delete [] a; //方式2...
  • httpClient工具类(delete传参)

    千次阅读 2018-07-12 18:05:15
    搞了半天的工具类,已测试,可直接使用 ... DeleteMethod deleteMethod = new DeleteMethod(url); List<org.apache.commons.httpclient.NameValuePair> data = new ArrayList(); if(dataForm!=null){ Set<String...
  • delete和Vue.delete删除数组的区别

    千次阅读 2019-08-31 17:22:36
    delete只是被删除的元素变成了 empty/undefined 其他的元素的键值还是不变。 Vue.delete 直接删除了数组 改变了数组的键值。 接下来我们来看一个例子 <template> <div class="vue-delete"> <p ...
  • 服务器 // 传统的URL app.delete('/axios', (req, res) => { res.send('axios delete 传递参数' + req.query.id) }) // Restful 的URL app.delete('/axios/:id', (req, res) => { res.send('axios delete(Restful) ...
  • C++ 中的创建和删除数组(new/delete 和 new[]/delete[])

    万次阅读 多人点赞 2018-06-12 21:27:36
    C++ 中的创建和删除数组(new/delete 和 new[]/delete[]) 已有 4122 次阅读 2017-4-17 16:33|个人分类:C++|系统分类:科研笔记|关键词:C++,数组,动态数组|数组, 动态数组 ...
  • 【C++】deletedelete []的真正区别

    千次阅读 2018-09-09 22:15:30
    c++中对new申请的内存的释放方式有deletedelete[两种方式,到底这两者有什么区别呢?   1.我们通常从教科书上看到这样的说明: delete 释放new分配的单个对象指针指向的内存 delete[] 释放new分配的对象数组...
  • vue 中 get / delete 传递数组参数方法

    千次阅读 2021-03-19 17:44:12
    在前后端交互的时候,有时候需要通过 get 或者 delete 传递一个数组给后台,但是这样直接传递后台无法接收数据,因为在传递的过程中数组参数会被转译,结果如下: 参数:{ name : [ 1, 2, 3 ] } 转译效果:...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,360,970
精华内容 944,388
关键字:

delete